<!DOCTYPE html>
<!-- saved from url=(0044)http://www.cnblogs.com/xueyoo/p/4815448.html -->
<html lang="zh-cn"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Boost学习之语法解析器--Spirit - xueyoo - 博客园</title>
<link type="text/css" rel="stylesheet" href="./Boost学习之语法解析器--Spirit - xueyoo - 博客园_files/blog-common.css">
<link id="MainCss" type="text/css" rel="stylesheet" href="./Boost学习之语法解析器--Spirit - xueyoo - 博客园_files/bundle-AnotherEon001.css">
<link id="mobile-style" media="only screen and (max-width: 768px)" type="text/css" rel="stylesheet" href="./Boost学习之语法解析器--Spirit - xueyoo - 博客园_files/bundle-AnotherEon001-mobile.css">
<link title="RSS" type="application/rss+xml" rel="alternate" href="http://www.cnblogs.com/xueyoo/rss">
<link title="RSD" type="application/rsd+xml" rel="EditURI" href="http://www.cnblogs.com/xueyoo/rsd.xml">
<link type="application/wlwmanifest+xml" rel="wlwmanifest" href="http://www.cnblogs.com/xueyoo/wlwmanifest.xml">
<script src="./Boost学习之语法解析器--Spirit - xueyoo - 博客园_files/jquery.js" type="text/javascript"></script>  
<script type="text/javascript">var currentBlogApp = 'xueyoo', cb_enable_mathjax=false;var isLogined=false;</script>
<script src="./Boost学习之语法解析器--Spirit - xueyoo - 博客园_files/blog-common.js" type="text/javascript"></script>
</head>
<body>
<a name="top"></a>

<div id="wrapper">
<div id="header">

<div id="top">
<h1><a id="Header1_HeaderTitle" class="headermaintitle" href="http://www.cnblogs.com/xueyoo/">xueyoo</a></h1>
<div id="subtitle"></div>
</div>
<div id="sub"><div id="blog_stats">
<div class="BlogStats">随笔 - 11, 文章 - 13, 评论 - 2, 引用 - 0</div>
</div></div>



</div>
<div id="main_container">
<div id="main_content">
<div id="content">
	
<div id="post_detail">
	<div class="post">
		<h2>
			<a id="cb_post_title_url" href="http://www.cnblogs.com/xueyoo/p/4815448.html">Boost学习之语法解析器--Spirit</a>
		</h2>
		<div class="postbody">
		<div id="cnblogs_post_body"><p>Boost.Spirit能使我们轻松地编写出一个简单脚本的语法解析器，它巧妙利用了元编程并重载了大量的C++操作符使得我们能够在C++里直接使用类似<strong>EBNF</strong>的语法构造出一个完整的语法解析器(同时也把C++弄得面目全非-_-)。<br>关于<strong>EBNF</strong>的内容大家可以到网上或书店里找：</p>
<p> EBNF基本形式&lt;符号&gt; ::= &lt;表达式&gt; 或 &lt;符号&gt; = &lt;表达式&gt;<br>表达式里常用的操作符有:</p>
<ol>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<strong>|</strong>&nbsp;&nbsp; 分隔符，表示由它分隔的某一个子表达式都可供选择</li>
<li> &nbsp; &nbsp;&nbsp;<strong>*</strong>&nbsp;&nbsp; 重复，和正则表达式里的*类似，表示它之前的子表达式可重复多次</li>
<li> &nbsp;&nbsp;&nbsp;&nbsp;<strong>-</strong>&nbsp;&nbsp; 排除，不允许出现跟在它后面的那个子表达式</li>
<li> &nbsp;&nbsp;&nbsp;&nbsp;<strong>,</strong>&nbsp;&nbsp; 串接，连接左右子表达式</li>
<li> &nbsp;&nbsp;&nbsp;&nbsp;<strong>;</strong>&nbsp;&nbsp; 终止符，一条规则定义结束</li>
<li> &nbsp;&nbsp;&nbsp;&nbsp;<strong>''</strong>&nbsp; 字符串</li>
<li> &nbsp;&nbsp;&nbsp;&nbsp;<strong>""</strong>&nbsp; 字符串</li>
<li> &nbsp;&nbsp;&nbsp;&nbsp;<strong>(...)</strong>&nbsp; 分组，就是平时括号的功能啦，改变优先级用的。</li>
<li> &nbsp;&nbsp;&nbsp;&nbsp;<strong>(*...*)</strong>&nbsp;注释</li>
<li> &nbsp;&nbsp;&nbsp;&nbsp;<strong>[...]</strong>&nbsp; 可选，综括号内的子表达式允许出现或不出现</li>
<li> &nbsp;&nbsp;&nbsp;&nbsp;<strong>{...}</strong>&nbsp; 重复，大括号内的子表达式可以多次出现</li>
<li> &nbsp;&nbsp;&nbsp;&nbsp;<strong>?...?</strong>&nbsp;&nbsp; 特殊字符，由ISO定义的一些特殊字例如:</li>








</ol>
<p>只允许赋值的简单编程语言可以用 EBNF 定义为:</p>
<ol class="dp-css">
<li>(* a simple program in EBNF ? Wikipedia *)</li>
<li>program = 'PROGRAM' , white space , identifier , white space ,</li>
<li>'BEGIN' , white space ,</li>
<li>{ assignment , ";" , white space } ,</li>
<li>'END.' ;</li>
<li>identifier = alphabetic character , [ { alphabetic character | digit } ] ;</li>
<li>number = [ "-" ] , digit , [ { digit } ] ;</li>
<li>string = '"' , { all characters ? '"' } , '"' ;</li>
<li>assignment = identifier , ":=" , ( number | identifier | string ) ;</li>
<li>alphabetic character = "A"|"B"|"C"|"D"|"E"|"F"|"G"|"H"|"I"|"J"|"K"|"L"|"M"|"N"|"O"|"P"|"Q"|"R"|"S"|"T"|"U"|"V"|"W"|"X"|"Y"|"Z" ;</li>
<li>digit = "0"|"1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9" ;</li>
<li>white space = ? white space characters ? ;</li>
<li>all characters = ? all visible characters ? ;</li>









</ol>
<p>一个语法上正确的程序:</p>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-delphi">
<li class="alt">PROGRAM&nbsp;DEMO1</li>
<li>BEGIN</li>
<li class="alt">&nbsp;&nbsp;A0:=<span class="number">3;</span></li>
<li>&nbsp;&nbsp;B:=<span class="number">45;</span></li>
<li class="alt">&nbsp;&nbsp;H:=-<span class="number">100023;</span></li>
<li>&nbsp;&nbsp;C:=A;</li>
<li class="alt">&nbsp;&nbsp;D123:=B34A;</li>
<li>&nbsp;&nbsp;BABOON:=GIRAFFE;</li>
<li class="alt">&nbsp;&nbsp;TEXT:="Hello&nbsp;world!";</li>
<li>END.</li>



</ol></div>













</div>
<p>
这个语言可以轻易的扩展上控制流，算术表达式和输入/输出指令。就可以开发出一个小的、可用的编程语言了。<br>&nbsp;<br>由于C++语法规则的限制，Spirit改变了EBNF中的一部分操作符的使用方式，如：</p>
<ul>
<li>星号重复符(*)由原来的后置改为前置</li>
<li>逗号串接符(,)由&gt;&gt;或&amp;&amp;代替</li>
<li>中括号可选功能([表达式])改为(!表达式)</li>
<li>大括号重复功能({表达式})由重复符(*表达式)替代</li>
<li>取消注释功能</li>
<li>取消特殊字符功能</li>
<li>同时Spirit又提供了大量的预置解析器加强了它的表达能力，因此可以把Spirit的语法看成是一种EBNF的变种。</li>



</ul>
<p>版本1.6.x之前的spirit能支持大部分的编译器。在1.8.0之后，由于spirit加入了很多C++的新特性，使兼容各种不标准的编译器的工作变得非常郁闷，于是Spirit不再支持不标准的C++编译器，这意味着VC7.1,BCB2006以及GCC3.1之前版本将不再被支持。（注：据说江湖上有新版Spirit的牛人修改版，可以工作在VC6和VC7上，具体情况不明）&nbsp;</p>
<p>&nbsp; <span style="font-size: 18pt;">&nbsp;<span style="color: #000000;"> <strong>入门</strong></span></span></p>
<p>&nbsp; &nbsp; 头文件:<br>&nbsp; &nbsp; #include &lt;boost/spirit.hpp&gt;</p>
<p>&nbsp; &nbsp; <em>例一，解析一个浮点数&nbsp;&nbsp;&nbsp; </em></p>
<p>&nbsp; &nbsp; 首先，要弄一个关于浮点数的<strong>EBNF规则</strong><br>&nbsp;&nbsp;&nbsp; 假设我们的浮点数形式是:&nbsp;[±]xxxx[.xxxx][Ex]，其中正负号可有可无，后面的幂可有可无，允许不带小数点<br>&nbsp;&nbsp;&nbsp; 则对应的EBNF规则是：<br>&nbsp;&nbsp;&nbsp; digit = "0"|"1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9";</p>
<p>&nbsp; &nbsp; real = ["+"|"-"], digit, [{digit}], [".", digit, [{digit}]], ["E"|"e", ["+"|"-"], digit, {digit}]&nbsp;&nbsp;&nbsp; </p>
<p>&nbsp; &nbsp; 那么对应在Spirit里的是什么样的呢？</p>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt">!(ch_p(<span class="string">'+')|ch_p(<span class="string">'－'))&gt;&gt;+digit_p&gt;&gt;!&nbsp;(ch_p(<span class="string">'.')&gt;&gt;+digit_p)&gt;&gt;</span></span></span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;!((ch_p(<span class="string">'e')|ch_p(<span class="string">'E'))&nbsp;&gt;&gt;&nbsp;!(ch_p(<span class="string">'+')|ch_p(<span class="string">'－'))&gt;&gt;+digit_p)</span></span></span></span></li>





</ol></div>





</div>
<p>&nbsp;&nbsp;&nbsp; 在<strong>Spirit</strong>中，用于匹配表达式的对象叫<strong>解析器</strong>，如这里的ch_p,&nbsp;digit_p以及由它们和操作符组成的整个或部分都可以称为<strong>解析器</strong>。</p>
<ol>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<strong>!</strong>符号代表其后的表达式是可选的，它代替了<strong>EBNF</strong>里的<strong>中括号</strong>功能。</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;ch_p()是一个<strong>Spirit</strong>预置的<strong>解析器生成函数</strong>，这个解析器用于<strong>匹配单个字符</strong>。</li>
<li><strong>&nbsp; &nbsp; &gt;&gt;</strong>用于代替<strong>逗号</strong>顺序连接后面的解析器</li>
<li><strong>&nbsp; &nbsp; +</strong>符号代表<strong>1次或多次</strong>重复</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;digit_p也是一个<strong>Spirit</strong>预置的<strong>解析器</strong>，它匹配<strong>数字字符</strong>。</li>





</ol>
<p>&nbsp;&nbsp;&nbsp; 这样，再看上面就好理解了：可选的+-号，接着是数字，再跟着是可选的小数点和数字，最后是可选的E跟一个可接+-号的数字<br><br>&nbsp;&nbsp;&nbsp; 现在，把这个式子写到代码里：</p>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt"><span class="preprocessor">#include &lt;iostream&gt;&nbsp;</span></li>
<li><span class="preprocessor">#include&nbsp;&lt;boost/spirit.hpp&gt;</span></li>
<li class="alt"><span class="keyword">using&nbsp;<span class="keyword">namespace&nbsp;std;</span></span></li>
<li><span class="keyword">using&nbsp;<span class="keyword">namespace&nbsp;boost::spirit;</span></span></li>
<li class="alt"><span class="datatypes">int&nbsp;main()</span></li>
<li>{</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;parse_info&lt;&gt;&nbsp;r&nbsp;=&nbsp;parse(<span class="string">"-12.33E-10",</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;!(ch_p(<span class="string">'+')|ch_p(<span class="string">'-'))&gt;&gt;+digit_p&gt;&gt;</span></span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;!(ch_p(<span class="string">'.')&gt;&gt;+digit_p)&gt;&gt;</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;!((ch_p(<span class="string">'e')|ch_p(<span class="string">'E'))&nbsp;&gt;&gt;</span></span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;!(ch_p(<span class="string">'+')|ch_p(<span class="string">'-'))&gt;&gt;+digit_p)</span></span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;<span class="string">"parsed&nbsp;"&nbsp;&lt;&lt;&nbsp;(r.full?<span class="string">"successful":<span class="string">"failed")&nbsp;&lt;&lt;&nbsp;endl;</span></span></span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return&nbsp;0;</span></li>
<li class="alt">}</li>










</ol></div>













</div>
<p>
&nbsp;&nbsp;&nbsp; 这就是Spirit,这个变种的EBNF语法直接就写在C++代码里就可以了，实际上它们是由一系列的<strong>简单解析器</strong>对象通过重载操作符后组合而成的<strong>复杂解析器</strong>。<br>&nbsp;&nbsp;&nbsp; 解析器重载的操作符也可以帮我们自动作一些转换工作，如上面的式子中ch_p('+')|ch_p('-')就可以改成ch_p('+')|'-'，只要左边或右边的数值其中之一是解析器，它就能自动和另一边的数值组合。<br>&nbsp;&nbsp;&nbsp; 简化后如下：</p>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt">!(ch_p(<span class="string">'+')|<span class="string">'-')&gt;&gt;+digit_p&gt;&gt;!(<span class="string">'.'&gt;&gt;+digit_p)&gt;&gt;!((ch_p(<span class="string">'e')|<span class="string">'E')&nbsp;&gt;&gt;&nbsp;!(ch_p(<span class="string">'+')|<span class="string">'-')&gt;&gt;+digit_p)</span></span></span></span></span></span></span></li>




</ol></div>




</div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>parse</strong>函数调用<strong>解析器</strong>来解析指定的字符串，它的原型是:</p>
<div class="HighLighter">
<div class="dp-highlighter"><ol>
<li class="alt">parse_info&lt;charT const*&gt; parse(字符串, 解析器);&nbsp;</li>
<li class="alt">parse_info&lt;charT const*&gt; parse(字符串, 解析器1, 解析器2);&nbsp;</li>




</ol></div>













</div>
<p>
&nbsp;&nbsp;&nbsp; 第二个版本中的解析器2指出解析时可以忽略的一些字符，比如语句中的空格之类的。<br>&nbsp;&nbsp;&nbsp; 另外，<strong>parse</strong>还有迭代器的版本</p>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt">parse_info&nbsp;parse(IteratorT&nbsp;first,&nbsp;IteratorT&nbsp;last,&nbsp;解析器);</li>
<li>parse_info&nbsp;parse(IteratorT&nbsp;first,&nbsp;IteratorT&nbsp;last,&nbsp;解析器1,&nbsp;解析器2); &nbsp;&nbsp;</li>




</ol></div>













</div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;IteratorT可以是任何迭代器类包括字符串指针，前面的这个两个版本其实只是简单地包装了一下这两个函数。<br>&nbsp;&nbsp;&nbsp; 返回的parse_info类（其中的IteratorT模板默认为char const*）包含了解析结果信息，里面的成员有:</p>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt">IteratorT&nbsp;&nbsp;&nbsp;stop;&nbsp;&nbsp;&nbsp;<span class="comment">//最后解析的位置</span></li>
<li><span class="datatypes">bool&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hit;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//是否与整个解析器匹配</span></span></li>
<li class="alt"><span class="datatypes">bool&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;full;&nbsp;&nbsp;&nbsp;<span class="comment">//是否与整个字符串匹配</span></span></li>
<li>std::<span class="datatypes">size_t&nbsp;length;&nbsp;<span class="comment">//解析器解析了多少个字符，注意，first+length不一定与stop相同</span></span></li>



</ol></div>



</div>
<p>&nbsp;&nbsp;&nbsp; 其实，<strong>Spirit</strong>已经帮我们准备好了很多解析器，比如上面我们写得要死的浮点数匹配，只要一个<strong>real_p</strong>就行了(冷静，冷静，上面的一长串到后面还是会用到的)</p>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt">parse_info&lt;&gt;&nbsp;r&nbsp;=&nbsp;parse(<span class="string">"-12.33E-10",real_p);</span></li>



</ol></div>



</div>
<p>Spirit预置的一些原始解析器，它们的名字都是以"<strong>xxxx_p</strong>"的形式出现。<br>字符解析器</p>
<ul>
<li>ch_p('X') 返回单字符解析器</li>
<li>range_p('a','z')&nbsp;&nbsp;&nbsp; 返回一个字符范围解析器，本例中匹配'a'..'z'</li>
<li>str_p("Hello World")&nbsp;&nbsp;&nbsp; 返回一个字符串解析器</li>
<li>chseq_p("ABCDEFG")&nbsp; 返回一个字符序列解析器，它可以匹配"ABCDEFG","A B C D E F G","AB CD EFG"等</li>
<li>anychar_p 匹配任何字符（包括'\0')</li>
<li>alnum_p 匹配A-Z,a-z,0-9</li>
<li>alpha_p 匹配字母</li>
<li>blank_p 匹配空格和TAB</li>
<li>cntrl_p 匹配控制字符</li>
<li>digit_p 匹配数字字符</li>
<li>graph_p 匹配可显示字符(除空格，回车，TAB等)</li>
<li>lower_p 匹配小写字符</li>
<li>print_p 匹配可打印字符</li>
<li>punct_p 匹配标点符号</li>
<li>space_p 匹配空格，回车，换行，TAB</li>
<li>upper_p 匹配大写字符</li>
<li>xdigit_p 匹配十六进制数字符串</li>
<li>eol_p&nbsp;&nbsp; 匹配行尾</li>
<li>nothing_p 不匹配任何字符，总是返回Fail(不匹配)</li>
<li>end_p&nbsp;&nbsp; 匹配结尾</li>













</ul>
<p>
字符解析器支持的操作符</p>
<ul>
<li>~a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 排除操作，如~ch_p('x')表示排除'x'字符</li>
<li>a|b&nbsp;&nbsp;&nbsp;&nbsp; 二选一操作，或称为联合，匹配a or b</li>
<li>a&amp;b &nbsp; &nbsp;交集，同时匹配a和b</li>
<li>a-b&nbsp;&nbsp;&nbsp;&nbsp; 差，匹配a但不匹配b</li>
<li>a^b &nbsp; &nbsp;异或，匹配a 或 匹配b，但不能两者同时匹配</li>
<li>a&gt;&gt;b &nbsp;序列连接，按顺序先匹配a，接下来的字符再匹配b</li>
<li>a&amp;&amp;b &nbsp;同上(象C语言一样，有短路效果，若a不匹配，则b不会被执行)</li>
<li>a||b &nbsp; &nbsp;连续或，按顺序先匹配a，接下来的字符匹配b(象C语言一样，有短路效果，若a已匹配，则b不会被执行)</li>
<li>*a &nbsp; &nbsp; &nbsp;匹配0次或多次</li>
<li>+a &nbsp; &nbsp; &nbsp;匹配1次或多次</li>
<li>!a &nbsp; &nbsp; &nbsp; 可选，匹配0或1次</li>
<li>a%b &nbsp; 列表，匹配a b a b a b a...，效果与 a &gt;&gt; *(b &gt;&gt; a)相同</li>













</ul>
<p>
整数解析器&nbsp;&nbsp;&nbsp;&nbsp;<strong>Spirit</strong>给我们准备了两个整数解析器类，对应于有符号数和无符号数int_parser和uint_parser<br>&nbsp;&nbsp;&nbsp; 它们都是模板类，定义如下：</p>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt"><span class="keyword">template&nbsp;&lt;</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">typename&nbsp;T&nbsp;=&nbsp;<span class="datatypes">int,</span></span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="datatypes">int&nbsp;Radix&nbsp;=&nbsp;10,</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;MinDigits&nbsp;=&nbsp;1,</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="datatypes">int&nbsp;MaxDigits&nbsp;=&nbsp;-1&gt;</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">struct&nbsp;int_parser;</span></li>
<li class="alt"><span class="keyword">template&nbsp;&lt;</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">typename&nbsp;T&nbsp;=&nbsp;unsigned,</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="datatypes">int&nbsp;Radix&nbsp;=&nbsp;10,</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;MinDigits&nbsp;=&nbsp;1,</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="datatypes">int&nbsp;MaxDigits&nbsp;=&nbsp;-1&gt;</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">struct&nbsp;uint_parser;</span></li>



</ol></div>













</div>
<p>
模板参数用法：</p>
<ul>
<li>T为数字类型</li>
<li>Radix为进制形式</li>
<li>MinDigits为最小长度</li>
<li>MaxDigits为最大长度，如果是-1表示不限制</li>



</ul>
<p>比如下面这个例子可以匹配象&nbsp;1,234,567,890&nbsp;这种形式的数字</p>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt">uint_parser&lt;unsigned,&nbsp;10,&nbsp;1,&nbsp;3&gt;&nbsp;uint3_p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;&nbsp;1..3&nbsp;digits</span></li>
<li>uint_parser&lt;unsigned,&nbsp;10,&nbsp;3,&nbsp;3&gt;&nbsp;uint3_3_p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;&nbsp;exactly&nbsp;3&nbsp;digits</span></li>
<li class="alt">ts_num_p&nbsp;=&nbsp;(uint3_p&nbsp;&gt;&gt;&nbsp;*(<span class="string">','&nbsp;&gt;&gt;&nbsp;uint3_3_p));&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;&nbsp;our&nbsp;thousand&nbsp;separated&nbsp;number&nbsp;parser</span></span></li>



</ol></div>













</div>
<p>
Spirit已预置的几个int_parser/uint_parser的特化版本：</p>
<ol>
<li><strong>int_p</strong>&nbsp;int_parser&lt;int, 10, 1, -1&gt;&nbsp;const</li>
<li><strong>bin_p</strong>&nbsp;uint_parser&lt;unsigned, 2, 1, -1&gt;&nbsp;const</li>
<li><strong>oct_p</strong>&nbsp;uint_parser&lt;unsigned, 8, 1, -1&gt;&nbsp;const</li>
<li><strong>uint_p</strong>&nbsp;uint_parser&lt;unsigned, 10, 1, -1&gt;&nbsp;const</li>
<li><strong>hex_p</strong>&nbsp;uint_parser&lt;unsigned, 16, 1, -1&gt;&nbsp;const </li>



</ol>
<p>实数解析器<strong>Spirit</strong>当然也会给我们准备实数解析器，定义如下：</p>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt"><span class="keyword">template&lt;</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">typename&nbsp;T&nbsp;=&nbsp;<span class="datatypes">double,</span></span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">typename&nbsp;RealPoliciesT&nbsp;=&nbsp;ureal_parser_policies&nbsp;&gt;</span></li>
<li><span class="keyword">struct&nbsp;real_parser;</span></li>



</ol></div>













</div>
<p>
模板参数用法：</p>
<ul>
<li>T表示实数类型</li>
<li>RealRoliciesT是一个策略类，目前不用深究，只要知道它决定了实数解析器的行为就行了。</li>













</ul>
<p>
已预置的实数解析器的特化版本：</p>
<ol>
<li><strong>ureal_p</strong>&nbsp;real_parser&lt;double, ureal_parser_policies&lt;double=""&gt;&nbsp;&gt; const</li>
<li><strong>real_p</strong>&nbsp;real_parser&lt;double, real_parser_policies&lt;double=""&gt;&nbsp;&gt; const</li>
<li><strong>strict_ureal_p</strong>&nbsp;real_parser&lt;double, strict_ureal_parser_policies&lt;double=""&gt;&nbsp;&gt; const</li>
<li><strong>strict_real_p</strong>&nbsp;real_parser&lt;double, strict_real_parser_policies&lt;double=""&gt;&nbsp;&gt; const</li>



</ol>
<p>&nbsp;&nbsp;&nbsp; real_p前面实例里已经见过，ureal_p是它的unsigned版本。strict_*则更严格地匹配实数（它不匹配整数）</p>
<div><em>例二，解析实数序列</em> &nbsp;</div>
<div>&nbsp; &nbsp; 有了上面的知识，我们可以试试解析以逗号分隔的实数序列<br>&nbsp;&nbsp;&nbsp; 字符串形式为"real,real,real,...real"<br>&nbsp;&nbsp;&nbsp; 参考上面的一堆预置解析器，我们可以这样组合：<br>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt">real_p&nbsp;&gt;&gt;&nbsp;*(<span class="string">','&nbsp;&gt;&gt;&nbsp;real_p);</span></li>



</ol></div>













</div>













&nbsp;&nbsp;&nbsp; 更简单点，我们可以使用%操作符
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt">real_p%<span class="string">','</span></li>



</ol></div>













</div>













&nbsp;&nbsp;&nbsp; 于是很简单地写下这样的代码:<br>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt">{</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//用于解析的字符串</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">const&nbsp;<span class="datatypes">char&nbsp;*szNumberList&nbsp;=&nbsp;<span class="string">"12.4,1000,-1928,33,30";</span></span></span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;parse_info&lt;&gt;&nbsp;r&nbsp;=&nbsp;parse(&nbsp;szNumberList,&nbsp;real_p&nbsp;%&nbsp;<span class="string">','&nbsp;);</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;<span class="string">"parsed&nbsp;"&nbsp;&lt;&lt;&nbsp;(r.full?<span class="string">"successful":<span class="string">"failed")&nbsp;&lt;&lt;&nbsp;endl;</span></span></span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;szNumberList&nbsp;&lt;&lt;&nbsp;endl;</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//使用parse_info::stop确定最后解析的位置便于查错</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;string(r.stop&nbsp;-&nbsp;szNumberList,&nbsp;<span class="string">'&nbsp;')&nbsp;&lt;&lt;&nbsp;<span class="string">'^'&nbsp;&lt;&lt;&nbsp;endl;&nbsp;</span></span></li>
<li class="alt">}</li>



</ol></div>













</div>













&nbsp;&nbsp;&nbsp; 解析成功！接下来我们就把里面的数字取出来，解析器重载了[]操作符，在这里可以放入<strong>函数或函数对象</strong>，放在这里面的函数或函数对象在Spirit里称之为<strong>Actor</strong><br>&nbsp;&nbsp;&nbsp; 对于real_p，它要求形式为:void func(double v)的<strong>函数或函数对象</strong>，下面我们就来取出这些数字：<br>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt"><span class="preprocessor">#include&nbsp;&lt;iostream&gt;</span></li>
<li><span class="preprocessor">#include&nbsp;&lt;boost/spirit.hpp&gt;</span></li>
<li class="alt"></li>
<li><span class="keyword">using&nbsp;<span class="keyword">namespace&nbsp;std;</span></span></li>
<li class="alt"><span class="keyword">using&nbsp;<span class="keyword">namespace&nbsp;boost::spirit;</span></span></li>
<li></li>
<li class="alt"><span class="comment">//定义函数作为解析器的Actor</span></li>
<li><span class="keyword">void&nbsp;showreal(<span class="datatypes">double&nbsp;v)</span></span></li>
<li class="alt">{</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;v&nbsp;&lt;&lt;&nbsp;endl;</li>
<li class="alt">}</li>
<li></li>
<li class="alt"><span class="datatypes">int&nbsp;main()</span></li>
<li>{</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//用于解析的字符串</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">const&nbsp;<span class="datatypes">char&nbsp;*szNumberList&nbsp;=&nbsp;<span class="string">"12.4,1000,-1928,33,30";&nbsp;</span></span></span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//加入函数</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;parse_info&lt;&gt;&nbsp;r&nbsp;=&nbsp;parse(&nbsp;szNumberList,&nbsp;real_p[&amp;showreal]&nbsp;%&nbsp;<span class="string">','&nbsp;);</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;<span class="string">"parsed&nbsp;"&nbsp;&lt;&lt;&nbsp;(r.full?<span class="string">"successful":<span class="string">"failed")&nbsp;&lt;&lt;&nbsp;endl;</span></span></span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;szNumberList&nbsp;&lt;&lt;&nbsp;endl;</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//使用parse_info::stop确定最后解析的位置便于查错</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;string(r.stop&nbsp;-&nbsp;szNumberList,&nbsp;<span class="string">'&nbsp;')&nbsp;&lt;&lt;&nbsp;<span class="string">'^'&nbsp;&lt;&lt;&nbsp;endl;</span></span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return&nbsp;0;</span></li>
<li>}</li>



</ol></div>













</div>













&nbsp;&nbsp;&nbsp; 再次运行，显示了一列数字了吧:)<br>&nbsp;&nbsp;&nbsp; 再写一个函数对象版本的，这次把这列数字写到<strong>vector</strong>里<br>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt"><span class="preprocessor">#include&nbsp;&lt;iostream&gt;</span></li>
<li><span class="preprocessor">#include&nbsp;&lt;vector&gt;</span></li>
<li class="alt"><span class="preprocessor">#include&nbsp;&lt;boost/spirit.hpp&gt;</span></li>
<li><span class="keyword">using&nbsp;<span class="keyword">namespace&nbsp;std;</span></span></li>
<li class="alt"><span class="keyword">using&nbsp;<span class="keyword">namespace&nbsp;boost::spirit;</span></span></li>
<li></li>
<li class="alt"><span class="datatypes">int&nbsp;main()</span></li>
<li>{</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;pushreal函数对象，把数字放入vector中</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">struct&nbsp;pushreal</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;{</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">void&nbsp;operator()(<span class="datatypes">double&nbsp;v)&nbsp;<span class="keyword">const</span></span></span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_vec.push_back(v);</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pushreal(vector&lt;<span class="datatypes">double&gt;&nbsp;&amp;vec)</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:m_vec(vec){;}</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">private:</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vector&lt;<span class="datatypes">double&gt;&nbsp;&amp;m_vec;</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;};</li>
<li class="alt"></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;vector&lt;<span class="datatypes">double&gt;&nbsp;reallist;</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//用于解析的字符串</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">const&nbsp;<span class="datatypes">char&nbsp;*szNumberList&nbsp;=&nbsp;<span class="string">"12.4,1000,-1928,33,30";</span></span></span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//这次用pushreal对象作为Actor</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;parse_info&lt;&gt;&nbsp;r&nbsp;=&nbsp;parse(&nbsp;szNumberList,&nbsp;real_p[pushreal(reallist)]&nbsp;%&nbsp;<span class="string">','&nbsp;);</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;<span class="string">"parsed&nbsp;"&nbsp;&lt;&lt;&nbsp;(r.full?<span class="string">"successful":<span class="string">"failed")&nbsp;&lt;&lt;&nbsp;endl;</span></span></span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;szNumberList&nbsp;&lt;&lt;&nbsp;endl;</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//使用parse_info::stop确定最后解析的位置便于查错</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;string(r.stop&nbsp;-&nbsp;szNumberList,&nbsp;<span class="string">'&nbsp;')&nbsp;&lt;&lt;&nbsp;<span class="string">'^'&nbsp;&lt;&lt;&nbsp;endl;</span></span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//显示结果</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;copy(reallist.begin(),reallist.end(),ostream_iterator&lt;<span class="datatypes">double&gt;(cout,<span class="string">"&nbsp;"));</span></span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return&nbsp;0;</span></li>
<li>}</li>



</ol></div>













</div>













&nbsp;&nbsp;&nbsp; 我不得不告诉你，<strong>Spirit</strong>也提供了比偶的这个pushreal强得多的函数对象<strong>push_back_a</strong>（需要冷静哈）<br>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt"><span class="preprocessor">#include&nbsp;&lt;iostream&gt;</span></li>
<li><span class="preprocessor">#include&nbsp;&lt;vector&gt;</span></li>
<li class="alt"><span class="preprocessor">#include&nbsp;&lt;boost/spirit.hpp&gt;</span></li>
<li><span class="keyword">using&nbsp;<span class="keyword">namespace&nbsp;std;</span></span></li>
<li class="alt"><span class="keyword">using&nbsp;<span class="keyword">namespace&nbsp;boost::spirit;</span></span></li>
<li><span class="datatypes">int&nbsp;main()</span></li>
<li class="alt">{</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;vector&lt;<span class="datatypes">double&gt;&nbsp;reallist;</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//用于解析的字符串</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">const&nbsp;<span class="datatypes">char&nbsp;*szNumberList&nbsp;=&nbsp;<span class="string">"12.4,1000,-1928,33,30";&nbsp;</span></span></span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//使用自带的push_back_a</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;parse_info&lt;&gt;&nbsp;r&nbsp;=&nbsp;parse(&nbsp;szNumberList,&nbsp;real_p[push_back_a(reallist)]&nbsp;%&nbsp;<span class="string">','&nbsp;);</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;<span class="string">"parsed&nbsp;"&nbsp;&lt;&lt;&nbsp;(r.full?<span class="string">"successful":<span class="string">"failed")&nbsp;&lt;&lt;&nbsp;endl;</span></span></span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;szNumberList&nbsp;&lt;&lt;&nbsp;endl;</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//使用parse_info::stop确定最后解析的位置便于查错</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;string(r.stop&nbsp;-&nbsp;szNumberList,&nbsp;<span class="string">'&nbsp;')&nbsp;&lt;&lt;&nbsp;<span class="string">'^'&nbsp;&lt;&lt;&nbsp;endl;</span></span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//显示结果</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;copy(reallist.begin(),reallist.end(),ostream_iterator&lt;<span class="datatypes">double&gt;(cout,<span class="string">"&nbsp;"));</span></span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return&nbsp;0;</span></li>
<li>}</li>



</ol></div>













</div>













&nbsp;&nbsp;&nbsp; 在上面的实数序列中，如果中间含有空格或TAB，这个解析就不能成功，这时可以使用<strong>parse</strong>函数的另一个重载版本：<br>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt">parse_info&lt;charT&nbsp;<span class="keyword">const*&gt;&nbsp;parse(字符串,&nbsp;解析器1,&nbsp;解析器2);</span></li>
<li><span class="comment">//或</span></li>
<li class="alt">parse_info&nbsp;parse(IteratorT&nbsp;first,&nbsp;IteratorT&nbsp;last,&nbsp;解析器1,&nbsp;解析器2); &nbsp;</li>



</ol></div>



</div>



&nbsp;&nbsp;&nbsp; 其中的解析器2用于跳过其匹配的字符，我们要跳过空格，所以解析器2可以使用<strong>space_p</strong>：<br>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt">parse_info&lt;&gt;&nbsp;r&nbsp;=&nbsp;parse(&nbsp;szNumberList,</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;real_p[push_back_a(reallist)]&nbsp;%&nbsp;<span class="string">',',</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;space_p);</li>



</ol></div>













</div>













&nbsp;&nbsp;&nbsp; 如果更进一步，我们甚至可以连逗号也跳过，直接取得一列数字：<br>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt">parse_info&lt;&gt;&nbsp;r&nbsp;=&nbsp;parse(&nbsp;szNumberList,</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;*real_p[push_back_a(reallist)],</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;space_p|ch_p(<span class="string">','));</span></li>



</ol></div>













</div>













除<strong>push_back_a</strong>外，<strong>Spirit</strong>还提供了不少有用的<strong>Actor</strong>（就是函数对象啦），如下<br>注：这里的<strong>ref</strong>是外部数据，就象上例中的reallist，<strong>value_ref</strong>是外部数值，<strong>value</strong>是解析出的数值
<ul>
<li>increment_a(ref)&nbsp;&nbsp;&nbsp; 自增&nbsp; ++ref</li>
<li>decrement_a(ref)&nbsp;&nbsp;&nbsp; 自减&nbsp; --ref</li>













</ul>













赋值操作
<ul>
<li>assign_a(ref) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 赋值&nbsp; ref = value</li>
<li>assign_a(ref, value_ref)&nbsp;&nbsp;&nbsp; 常量赋值&nbsp; ref = value_ref</li>













</ul>













容器操作
<ul>
<li>push_back_a(ref) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ref.push_back(value)</li>
<li>push_back_a(ref, value_ref)&nbsp;&nbsp;&nbsp; ref.push_back(value_ref)</li>
<li>push_front_a(ref) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ref.push_front(value)</li>
<li>push_front_a(ref, value_ref) &nbsp; ref.push_front(value_ref)</li>
<li>clear_a(ref) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ref.clear()</li>













</ul>













关联容器操作(vt类型是typeof(ref)::value_type)
<ul>
<li>insert_key_a(ref, value_ref) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ref.insert(vt(value, value_ref))</li>
<li>insert_at_a(ref, key_ref_, value_ref)&nbsp;&nbsp;&nbsp; ref.insert(vt(key_ref,value_ref))</li>
<li>insert_at_a(ref, key_ref) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ref.insert(vt(key_ref,value))</li>
<li>assign_key_a(ref, value_ref) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ref[value] = value_ref</li>
<li>erase_a(ref) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ref.erase(ref,value)</li>
<li>erase_a(ref, key_ref) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ref.erase(ref,key_ref)</li>













</ul>













其它操作
<ul>
<li>swap_a(aref, bref)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 交换aref和bref</li>



</ul>
<p>例三，四则运算 &nbsp;&nbsp;</p>
<p>如果说上面的两个例子用<a href="http://www.cppprog.com/2009/0116/53.html"><strong>正则表达式</strong></a>也能轻松搞定了话，那么接下来你就能体会到<strong>Spirit</strong>的强大威力！<br>&nbsp;&nbsp;&nbsp; 解析四则运算表达式，同样先要把<strong>EBNF</strong>规则写出来：</p>
<ul>
<li>//实数或者是括号包围的子表达式</li>
<li>因子 = 实数 | '(' , 表达式 , ')'; </li>
<li>//因子*因子或因子/因子，可连续乘除也可只是一个因子</li>
<li>乘除计算 = 因子,{('*',因子)|('/',因子)}; </li>
<li>//加减计算，与上面类似</li>
<li>表达式 = 乘除计算,{('+',乘除计算)|('-',乘除计算)};&nbsp;&nbsp;&nbsp; </li>



</ul>
<p>这个定义已经隐含了优先级:</p>
<ul>
<li>要计算表达式(加减计算),必然要先计算乘除计算;</li>
<li>要计算乘除计算，就要先计算因子;</li>
<li>要计算因子，要么得到一个数字，要么就要计算括号内的子表达式。</li>



</ul>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 转成Spirit解析器组合：</p>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt">rule&lt;phrase_scanner_t&gt;&nbsp;factor,&nbsp;term,&nbsp;exp;</li>
<li>factor&nbsp;=&nbsp;real_p&nbsp;|&nbsp;(<span class="string">'('&nbsp;&gt;&gt;&nbsp;exp&nbsp;&gt;&gt;&nbsp;<span class="string">')');</span></span></li>
<li class="alt">term&nbsp;&nbsp;&nbsp;=&nbsp;factor&nbsp;&gt;&gt;&nbsp;*((<span class="string">'*'&nbsp;&gt;&gt;&nbsp;factor)&nbsp;|&nbsp;(<span class="string">'/'&nbsp;&gt;&gt;&nbsp;factor));</span></span></li>
<li>exp&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;term&nbsp;&gt;&gt;&nbsp;*((<span class="string">'+'&nbsp;&gt;&gt;&nbsp;term)&nbsp;|&nbsp;(<span class="string">'-'&nbsp;&gt;&gt;&nbsp;term));</span></span></li>



</ol></div>



</div>
<p>&nbsp;&nbsp;&nbsp; 这里的<strong>rule</strong>是一个规则类，它可以作为<strong>所有解析器的占位符</strong>，定义如下：</p>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt"><span class="keyword">template&lt;</span></li>
<li><span class="keyword">typename&nbsp;ScannerT&nbsp;=&nbsp;scanner&lt;&gt;,</span></li>
<li class="alt"><span class="keyword">typename&nbsp;ContextT&nbsp;=&nbsp;parser_context&lt;&gt;,</span></li>
<li><span class="keyword">typename&nbsp;TagT&nbsp;=&nbsp;parser_address_tag&gt;</span></li>
<li class="alt"><span class="keyword">class&nbsp;rule;</span></li>



</ol></div>



</div>
<p>









&nbsp;&nbsp;&nbsp; 其中的模板参数作用是：<br><strong>ScannerT</strong>&nbsp;&nbsp;&nbsp; 扫描器策略类<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 它有两类工作模式，一种是<strong>字符模式</strong>，一种是<strong>语法模式</strong>，默认的scanner&lt;&gt;是工作于<strong>字符模式</strong>的。<br><strong>ContextT&nbsp;</strong>&nbsp;&nbsp; 内容策略类<br>&nbsp; &nbsp; &nbsp; &nbsp; 它决定了rule里的成员变量以及Actor的类型，稍后会有利用这个模板参数来加入自定义的成员变量的例子<br><strong>TagT</strong>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 标识策略类<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 每个rule都有一个id()方法，用于识别不同的rule，TagT就用于决定id()返回的数据（后面会讲到）。<br>&nbsp;&nbsp;&nbsp; 这三个策略类可以不按顺序地输入，如</p>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt">rule&lt;parser_address_tag,parser_context&lt;&gt;,scanner&lt;&gt;&nbsp;&gt;;</li>
<li>rule&lt;parser_context&lt;&gt;&nbsp;&gt;;</li>
<li class="alt">rule&lt;scanner&lt;&gt;,parser_address_tag&nbsp;&gt;;</li>



</ol></div>



</div>
<p>









&nbsp;&nbsp;&nbsp; 是同一个类。<br>&nbsp;&nbsp;&nbsp; 值得注意的是ScannerT,我们上面没有使用默认的scanner&lt;&gt;，而是使用了<strong>phrase_scanner_t</strong>，因为工作于<strong>字符模式</strong>的扫描器无法与parse的解析器2参数（跳过匹配字符，见上）一同工作，这样就无法解析含有空格的表达式，这可不完美，所以我们使用的工作于<strong>语法模式</strong>的<strong>phrase_scanner_t</strong>。</p>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt"><span class="preprocessor">#include&nbsp;&lt;iostream&gt;</span></li>
<li><span class="preprocessor">#include&nbsp;&lt;vector&gt;</span></li>
<li class="alt"><span class="preprocessor">#include&nbsp;&lt;boost/spirit.hpp&gt;</span></li>
<li><span class="keyword">using&nbsp;<span class="keyword">namespace&nbsp;std;</span></span></li>
<li class="alt"><span class="keyword">using&nbsp;<span class="keyword">namespace&nbsp;boost::spirit;</span></span></li>
<li><span class="datatypes">int&nbsp;main()</span></li>
<li class="alt">{</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;rule&lt;phrase_scanner_t&gt;&nbsp;factor,&nbsp;term,&nbsp;exp;</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;factor&nbsp;=&nbsp;real_p&nbsp;|&nbsp;(<span class="string">'('&nbsp;&gt;&gt;&nbsp;exp&nbsp;&gt;&gt;&nbsp;<span class="string">')');</span></span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;term&nbsp;&nbsp;&nbsp;=&nbsp;factor&nbsp;&gt;&gt;&nbsp;*((<span class="string">'*'&nbsp;&gt;&gt;&nbsp;factor)&nbsp;|&nbsp;(<span class="string">'/'&nbsp;&gt;&gt;&nbsp;factor));</span></span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;exp&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;term&nbsp;&gt;&gt;&nbsp;*((<span class="string">'+'&nbsp;&gt;&gt;&nbsp;term)&nbsp;|&nbsp;(<span class="string">'-'&nbsp;&gt;&gt;&nbsp;term));</span></span></li>
<li class="alt"><span class="keyword">&nbsp; &nbsp; const&nbsp;<span class="datatypes">char&nbsp;*szExp&nbsp;=&nbsp;<span class="string">"1&nbsp;+&nbsp;(2&nbsp;*&nbsp;(3&nbsp;/&nbsp;(4&nbsp;+&nbsp;5)))";</span></span></span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;parse_info&lt;&gt;&nbsp;r&nbsp;=&nbsp;parse(&nbsp;szExp&nbsp;,&nbsp;exp,&nbsp;space_p);</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;<span class="string">"parsed&nbsp;"&nbsp;&lt;&lt;&nbsp;(r.full?<span class="string">"successful":<span class="string">"failed")&nbsp;&lt;&lt;&nbsp;endl;</span></span></span></li>
<li class="alt"><span class="keyword">&nbsp; &nbsp; return&nbsp;0;</span></li>
<li>}</li>



</ol></div>



</div>
<p>&nbsp;&nbsp;&nbsp; 接下来，要得到这个四则表达式的计算结果，这才是我们要的，于是<strong>Spirit</strong>自带的lambda支持：<strong>phoenix</strong>登场！<br><br>&nbsp;&nbsp;&nbsp; 头文件：<br>&nbsp; &nbsp; #include &lt;boost/spirit/phoenix.hpp&gt;&nbsp; &nbsp; &nbsp;</p>
<p><strong>&nbsp; &nbsp; phoenix</strong>提供和与<strong>Boost.Lambda</strong>类似的功能，它可以直接就地生成<strong>匿名函数对象</strong>，<strong>phoenix</strong>使用arg1,arg2,arg3...作为占位符，<strong>Boost.Lambda</strong>则使用_1,_2,_3...，使用举例：</p>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt"><span class="preprocessor">#include&nbsp;&lt;iostream&gt;</span></li>
<li><span class="preprocessor">#include&nbsp;&lt;vector&gt;</span></li>
<li class="alt"><span class="preprocessor">#include&nbsp;&lt;boost/spirit.hpp&gt;</span></li>
<li><span class="preprocessor">#include&nbsp;&lt;boost/spirit/phoenix.hpp&gt;</span></li>
<li class="alt"><span class="keyword">using&nbsp;<span class="keyword">namespace&nbsp;std;</span></span></li>
<li><span class="keyword">using&nbsp;<span class="keyword">namespace&nbsp;boost::spirit;</span></span></li>
<li class="alt"><span class="keyword">using&nbsp;<span class="keyword">namespace&nbsp;phoenix;</span></span></li>
<li><span class="datatypes">int&nbsp;main()</span></li>
<li class="alt">{</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;vector&lt;<span class="datatypes">int&gt;&nbsp;vec(10);</span></li>
<li class="alt"><span class="datatypes">&nbsp; &nbsp; int&nbsp;i=0;</span></li>
<li><span class="comment">&nbsp; &nbsp; //arg1&nbsp;=&nbsp;var(i)++&nbsp;把i++赋值给vec里各单元</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;for_each(vec.begin(),vec.end(),arg1&nbsp;=&nbsp;var(i)++);</li>
<li><span class="comment">&nbsp; &nbsp; //cout&lt;&lt;arg1&lt;&lt;endl&nbsp;把vec各单元输出至cout</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;for_each(vec.begin(),vec.end(),cout&nbsp;&lt;&lt;&nbsp;arg1&nbsp;&lt;&lt;&nbsp;endl);</li>
<li class="alt"><span class="keyword">&nbsp; &nbsp; return&nbsp;0;</span></li>
<li>}</li>



</ol></div>



</div>
<p>&nbsp;&nbsp;&nbsp; 这样我们就可以利用<strong>phoenix</strong>提供的匿名函数对象作为<strong>Actor</strong>, 同时利用<strong>Spirit</strong>提供的<strong>closure</strong>类为rule添加一个val成员变量存储计算结果（还记得rule的ContextT策略吗？）</p>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt"><span class="preprocessor">#include&nbsp;&lt;iostream&gt;</span></li>
<li><span class="preprocessor">#include&nbsp;&lt;vector&gt;</span></li>
<li class="alt"><span class="preprocessor">#include&nbsp;&lt;boost/spirit.hpp&gt;</span></li>
<li><span class="preprocessor">#include&nbsp;&lt;boost/spirit/phoenix.hpp&gt;</span></li>
<li class="alt"><span class="keyword">using&nbsp;<span class="keyword">namespace&nbsp;std;</span></span></li>
<li><span class="keyword">using&nbsp;<span class="keyword">namespace&nbsp;boost::spirit;</span></span></li>
<li class="alt"><span class="keyword">using&nbsp;<span class="keyword">namespace&nbsp;phoenix;</span></span></li>
<li><span class="datatypes">int&nbsp;main()</span></li>
<li class="alt">{</li>
<li><span class="comment">&nbsp; &nbsp; //为rule准备一个val变量，类型为double</span></li>
<li class="alt"><span class="comment">&nbsp; &nbsp; //准确地说：是一个phoenix类(这里的member1)，它和其它phoenix类组成lambda表达式，在lambda中可以把它看成是一个double。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li>
<li><span class="keyword">&nbsp; &nbsp; struct&nbsp;calc_closure&nbsp;:&nbsp;boost::spirit::closure&lt;calc_closure,&nbsp;<span class="datatypes">double&gt;</span></span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;{</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;member1&nbsp;val;</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;};</li>
<li class="alt"><span class="comment">&nbsp; &nbsp; //定义ContextT策略为calc_closure::context_t</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;rule&lt;phrase_scanner_t,&nbsp;calc_closure::context_t&gt;&nbsp;factor,&nbsp;term,&nbsp;exp;</li>
<li><span class="comment">&nbsp; &nbsp; //直接使用phoenix的lambda表达式作为Actor</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;factor&nbsp;=&nbsp;real_p[factor.val&nbsp;=&nbsp;arg1]&nbsp;|&nbsp;(<span class="string">'('&nbsp;&gt;&gt;&nbsp;exp[factor.val&nbsp;=&nbsp;arg1]&nbsp;&gt;&gt;&nbsp;<span class="string">')');</span></span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;term&nbsp;&nbsp;&nbsp;=&nbsp;factor[term.val&nbsp;=&nbsp;arg1]&nbsp;&gt;&gt;&nbsp;*((<span class="string">'*'&nbsp;&gt;&gt;&nbsp;factor[term.val&nbsp;*=&nbsp;arg1])&nbsp;|&nbsp;(<span class="string">'/'&nbsp;&gt;&gt;&nbsp;factor[term.val&nbsp;/=&nbsp;arg1]));</span></span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;exp&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;term[exp.val&nbsp;=&nbsp;arg1]&nbsp;&gt;&gt;&nbsp;*((<span class="string">'+'&nbsp;&gt;&gt;&nbsp;term[exp.val&nbsp;+=&nbsp;arg1])&nbsp;|&nbsp;(<span class="string">'-'&nbsp;&gt;&gt;&nbsp;term[exp.val&nbsp;-=&nbsp;arg1]));</span></span></li>
<li class="alt"><span class="keyword">&nbsp; &nbsp; const&nbsp;<span class="datatypes">char&nbsp;*szExp&nbsp;=&nbsp;<span class="string">"1&nbsp;+&nbsp;(2&nbsp;*&nbsp;(3&nbsp;/&nbsp;(4&nbsp;+&nbsp;5)))";</span></span></span></li>
<li><span class="datatypes">&nbsp; &nbsp; double&nbsp;result;</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;parse_info&lt;&gt;&nbsp;r&nbsp;=&nbsp;parse(&nbsp;szExp&nbsp;,&nbsp;exp[assign_a(result)],&nbsp;space_p);</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;szExp;</li>
<li><span class="keyword">&nbsp; &nbsp; if(r.full)</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;{</li>
<li><span class="comment">&nbsp; &nbsp; &nbsp; &nbsp; //成功，得到结果</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;<span class="string">"&nbsp;=&nbsp;"&nbsp;&lt;&lt;&nbsp;result&nbsp;&lt;&lt;&nbsp;endl;</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;}</li>
<li class="alt"><span class="keyword">&nbsp; &nbsp; else</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;{</li>
<li class="alt"><span class="comment">&nbsp; &nbsp; &nbsp; &nbsp; //失败，显示错误位置</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;endl&nbsp;&lt;&lt;&nbsp;string(r.stop&nbsp;-&nbsp;szExp,&nbsp;<span class="string">'&nbsp;')&nbsp;&lt;&lt;&nbsp;<span class="string">'^'&nbsp;&lt;&lt;&nbsp;endl;</span></span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;}</li>
<li><span class="keyword">&nbsp; &nbsp; return&nbsp;0;</span></li>
<li class="alt">}</li>



</ol></div>



</div>
<p>









&nbsp;&nbsp;&nbsp; 感到很神奇？这里有必要多说一下<strong>boost::spirit::closure</strong>的作用，它的使用方法是:</p>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt"><span class="keyword">struct&nbsp;name&nbsp;:&nbsp;spirit::closure&lt;name,&nbsp;type1,&nbsp;type2,&nbsp;type3,...&nbsp;typen&gt;</span></li>
<li>{</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;member1&nbsp;m_name1;</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;member2&nbsp;m_name2;</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;member3&nbsp;m_name3;</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;...</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;memberN&nbsp;m_nameN;</li>
<li>};</li>



</ol></div>



</div>
<p>









&nbsp;&nbsp;&nbsp; 一种类型对应一个member,使用name::context_t作为ContextT策略的rule就会含有N个相应的变量，而且这个rule的<strong>Actor</strong>将会接收到member1对应的数据。<br>&nbsp;&nbsp;&nbsp; 也可以用于语法类，如grammar&lt;t, name::context_t=""&gt;，关于语法类，后面章节将会提到。<br>&nbsp;&nbsp;&nbsp;&nbsp;注：默认最多到member3，要想使用更多数据，在包含<strong>Spirit</strong>头文件前预定义PHOENIX_LIMIT和BOOST_SPIRIT_CLOSURE_LIMIT，如</p>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt"><span class="preprocessor">#define&nbsp;PHOENIX_LIMIT&nbsp;10</span></li>
<li><span class="preprocessor">#define&nbsp;BOOST_SPIRIT_CLOSURE_LIMIT&nbsp;10</span></li>



</ol></div>



</div>













</div>
<div>提高 例四，使用自定义语法类框架
<div>&nbsp;&nbsp;&nbsp; 在<a href="http://www.cppprog.com/2009/0121/55_4.html">例三</a>中，我们用了不足50行的代码搞定了一个四则运算字符串的解析，可见Spirit的威力巨大。不过仅仅这样还不够，Spirit可是号称轻量语法解析库，一个基本可用的脚本可不止四则运算那么点东西，起码要有赋值、条件、循环、输入输出吧？<br>&nbsp;&nbsp;&nbsp; 有了上面的知识，再加上一些编程经验，一个个搞定它们应该不是太难的事，但把所有的规则堆在一起不仅恶心，而且难以维护，于是Spirit提供了语法类<strong>grammar</strong>来集中管理。<br>&nbsp;&nbsp;&nbsp;&nbsp;<strong>grammar</strong>的定义如下：</div>
<div>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt"><span class="keyword">template&lt;</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">typename&nbsp;DerivedT,</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">typename&nbsp;ContextT&nbsp;=&nbsp;parser_context&lt;&gt;&nbsp;&gt;</span></li>
<li><span class="keyword">struct&nbsp;grammar;</span></li>



</ol></div>













</div>













</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;DerivedT参数是反引用自身类型，如果用过<strong>WTL</strong>库的可能对这个比较熟悉，使用这种技术可以保持多态性的同时消除虚函数带来的性能开稍。<br>&nbsp;&nbsp;&nbsp;&nbsp;ContextT参数就是<strong>内容策略类</strong>，在<a href="http://www.cppprog.com/2009/0121/55_4.html">例三</a>中提到过。<br>&nbsp;&nbsp;&nbsp; 编写一个<strong>语法类框架</strong>的基本形式如下：</div>
<div>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt"><span class="keyword">struct&nbsp;my_grammar&nbsp;:&nbsp;<span class="keyword">public&nbsp;grammar&lt;my_grammar&gt;</span></span></li>
<li>{</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">template&nbsp;&lt;<span class="keyword">typename&nbsp;ScannerT&gt;</span></span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">struct&nbsp;definition</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;{</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rule&nbsp;&nbsp;r;</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;definition(my_grammar&nbsp;<span class="keyword">const&amp;&nbsp;self)&nbsp;&nbsp;{&nbsp;r&nbsp;=&nbsp;<span class="comment">/*..define&nbsp;here..*/;&nbsp;}</span></span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rule&nbsp;<span class="keyword">const&amp;&nbsp;start()&nbsp;<span class="keyword">const&nbsp;{&nbsp;<span class="keyword">return&nbsp;r;&nbsp;}</span></span></span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;};</li>
<li>};</li>



</ol></div>













</div>













</div>
<div>&nbsp;&nbsp;&nbsp; 它继承自<strong>grammar</strong>,模板参数DerivedT就是自身类型，ContextT可以使用默认的parser_context&lt;&gt;或者自己定义一个(比如<a href="http://www.cppprog.com/2009/0121/55_4.html">例三</a>中的<strong>closure</strong>)。<br>&nbsp;&nbsp;&nbsp; 这个类内部必须要有一个<strong>definition</strong>类的定义，这个<strong>definition</strong>类的模板参数ScannerT由框架使用环境决定。它由两个重要方法：</div>
<ul>
<li>start() const函数：它返回一个rule。使用my_grammar解析时，就从这个rule开始。</li>
<li>definition构造函数：这里是初始化rule的最好场所。它的self参数是整个my_grammar的实例引用，接下去你会发现这可是个很有用的东西。</li>













</ul>
<div>&nbsp;&nbsp;&nbsp; 同时，很重要的一点：<strong>语法类</strong>本身也是一个<strong>解析器</strong>，它也能与其它<strong>解析器</strong>组合。<br><br>&nbsp;&nbsp;&nbsp; 下面，我们把例三中的四则运算解析功能放到一个语法类中，然后再用这个语法类与其它解析器合作弄一个简单的赋值操作出来：</div>
<div>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt"><span class="preprocessor">#include&nbsp;&lt;iostream&gt;</span></li>
<li><span class="preprocessor">#include&nbsp;&lt;boost/spirit.hpp&gt;</span></li>
<li class="alt"><span class="preprocessor">#include&nbsp;&lt;boost/spirit/phoenix.hpp&gt;</span></li>
<li><span class="keyword">using&nbsp;<span class="keyword">namespace&nbsp;std;</span></span></li>
<li class="alt"><span class="keyword">using&nbsp;<span class="keyword">namespace&nbsp;boost::spirit;</span></span></li>
<li><span class="keyword">using&nbsp;<span class="keyword">namespace&nbsp;phoenix;</span></span></li>
<li class="alt"></li>
<li><span class="comment">//closure，为解析器提供存储策略，见例三</span></li>
<li class="alt"><span class="keyword">struct&nbsp;calc_closure&nbsp;:&nbsp;boost::spirit::closure&lt;calc_closure,&nbsp;<span class="datatypes">double&gt;</span></span></li>
<li>{</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;member1&nbsp;val;</li>
<li>};</li>
<li class="alt"><span class="comment">//四则运算语法类，它也使用了closure的内容策略</span></li>
<li><span class="keyword">struct&nbsp;calculator&nbsp;:&nbsp;<span class="keyword">public&nbsp;grammar&lt;calculator,&nbsp;calc_closure::context_t&gt;</span></span></li>
<li class="alt">{</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//语法类重要成员:struct&nbsp;definition</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">template&nbsp;&lt;<span class="keyword">typename&nbsp;ScannerT&gt;</span></span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">struct&nbsp;definition</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;{</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;factor,&nbsp;term,&nbsp;exp的rule类型，同例三(ScannerT模板在使用时决定)</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">typedef&nbsp;rule&lt;scannert,&nbsp;calc_closure::context_t&gt;&nbsp;rule_type;</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rule_type&nbsp;factor,&nbsp;term,&nbsp;exp;</li>
<li class="alt"></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;启动rule，在这个例子中，它也是递归的最顶层，负责把exp的最终结果赋值给框架本身。</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rule&nbsp;rlStart;</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">const&nbsp;rule&amp;&nbsp;start()&nbsp;<span class="keyword">const&nbsp;{&nbsp;<span class="keyword">return&nbsp;rlStart;&nbsp;}</span></span></span></li>
<li class="alt"></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//definition的构造函数，self参数引用的是calculator类的实例</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;definition(calculator&nbsp;<span class="keyword">const&amp;&nbsp;self)</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;四则运算规则定义与例三相同</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;factor&nbsp;=&nbsp;real_p[factor.val&nbsp;=&nbsp;arg1]&nbsp;|</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(<span class="string">'('&nbsp;&gt;&gt;&nbsp;exp[factor.val&nbsp;=&nbsp;arg1]&nbsp;&gt;&gt;&nbsp;<span class="string">')');</span></span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;term&nbsp;&nbsp;&nbsp;=&nbsp;factor[term.val&nbsp;=&nbsp;arg1]&nbsp;&gt;&gt;</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*((<span class="string">'*'&nbsp;&gt;&gt;&nbsp;factor[term.val&nbsp;*=&nbsp;arg1])&nbsp;|</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(<span class="string">'/'&nbsp;&gt;&gt;&nbsp;factor[term.val&nbsp;/=&nbsp;arg1]));</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exp&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;term[exp.val&nbsp;=&nbsp;arg1]&nbsp;&gt;&gt;</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*((<span class="string">'+'&nbsp;&gt;&gt;&nbsp;term[exp.val&nbsp;+=&nbsp;arg1])&nbsp;|</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(<span class="string">'-'&nbsp;&gt;&gt;&nbsp;term[exp.val&nbsp;-=&nbsp;arg1]));</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//self.val=arg1也是phoenix的匿名函数：把exp的结果赋值给框架本身（self的作用）</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rlStart&nbsp;&nbsp;=&nbsp;exp[self.val&nbsp;=&nbsp;arg1];</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;};</li>
<li>};</li>
<li class="alt"></li>
<li><span class="datatypes">int&nbsp;main()</span></li>
<li class="alt">{</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;string&nbsp;strVar;&nbsp;<span class="comment">//变量名</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="datatypes">double&nbsp;result;&nbsp;<span class="comment">//结果</span></span></li>
<li></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;calculator&nbsp;calc;</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;赋值语法：变量名&nbsp;=&nbsp;表达式</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;rule&lt;phrase_scanner_t&gt;&nbsp;rlEqu&nbsp;=&nbsp;&nbsp;(+alpha_p)[assign(strVar)]&nbsp;&gt;&gt;&nbsp;<span class="string">'='&nbsp;&gt;&gt;&nbsp;calc[assign_a(result)];</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">const&nbsp;<span class="datatypes">char&nbsp;*szEqu&nbsp;=&nbsp;<span class="string">"value&nbsp;=&nbsp;1&nbsp;+&nbsp;(2&nbsp;*&nbsp;(3&nbsp;/&nbsp;(4&nbsp;+&nbsp;5)))";</span></span></span></li>
<li class="alt"></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;parse_info&lt;&gt;&nbsp;r&nbsp;=&nbsp;parse(&nbsp;szEqu&nbsp;,&nbsp;rlEqu,&nbsp;space_p);</li>
<li class="alt"></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if(r.full)&nbsp;<span class="comment">//成功，得到结果</span></span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;strVar&nbsp;&lt;&lt;&nbsp;<span class="string">"&nbsp;=&nbsp;"&nbsp;&lt;&lt;&nbsp;result&nbsp;&lt;&lt;&nbsp;endl;</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">else&nbsp;&nbsp;<span class="comment">//失败，显示错误位置</span></span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;endl&nbsp;&lt;&lt;&nbsp;string(r.stop&nbsp;-&nbsp;szEqu,&nbsp;<span class="string">'&nbsp;')&nbsp;&lt;&lt;&nbsp;<span class="string">'^'&nbsp;&lt;&lt;&nbsp;endl;</span></span></li>
<li class="alt"></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return&nbsp;0;</span></li>
<li>}</li>



</ol></div>



</div>



</div>
<div>&nbsp;&nbsp;&nbsp; 如果没拼写出错的话，应该会显示出"value = 1.66667"。</div>
<div>&nbsp;</div>



<em>&nbsp; &nbsp; 例五，在四则运算表达式中使用变量</em>
<div>&nbsp;&nbsp;&nbsp; 在例四中，我们可以解析"变量名 = 表达式"这种形式的语句。现在，我们再进一步，允许在表达式中使用变量，如value = value * pi + 5<br>&nbsp;&nbsp;&nbsp; 那么，还是先从规则动手。<br>&nbsp;&nbsp;&nbsp; 这里我把变量名的规则放松了一点，<span style="text-decoration: underline;">例四</span>里变量名只能用字母，这里除了第一位是字母后面允许使用数字。于是变量名规则写成(alpha_p &gt;&gt; *(alnum_p))<br>&nbsp;&nbsp;&nbsp; 变量代表的是一个数值，它和实数应该属于同一级别，所以我们把变量规则加入到factor规则里：</div>
<div>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt">factor&nbsp;=&nbsp;real_p[factor.val&nbsp;=&nbsp;arg1]&nbsp;|</li>
<li><span class="comment">//&nbsp;在表达式中使用变量</span></li>
<li class="alt">(alpha_p&nbsp;&gt;&gt;&nbsp;*(alnum_p))[<span class="comment">/*这里写什么呢*/]|</span></li>
<li>(<span class="string">'('&nbsp;&gt;&gt;&nbsp;exp[factor.val&nbsp;=&nbsp;arg1]&nbsp;&gt;&gt;&nbsp;<span class="string">')');</span></span></li>



</ol></div>



</div>



</div>
<div>&nbsp;&nbsp;&nbsp; 那么，变量名对应的<strong>Actor</strong>写什么呢？具体地说是"factor.val = 什么"呢？<br>&nbsp;&nbsp;&nbsp; 对了，我们只要把变量名和它的数值一一对应起来，那么这里只要把此变量名对应的数值送给factor.val就行了，标准库里的<strong>map</strong>在这里用是再适合不过了。<br>&nbsp;&nbsp;&nbsp; 为了把变量和它的数值放到<strong>map</strong>里，main里的rlEqu规则我们也要小改改：</div>
<div>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt">rule&lt;phrase_scanner_t&gt;&nbsp;rlEqu&nbsp;=</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;((alpha_p&nbsp;&gt;&gt;&nbsp;*(alnum_p))[assign(strVar)]&nbsp;&gt;&gt;</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="string">'='&nbsp;&gt;&gt;&nbsp;calc[assign_a(result)]&nbsp;)&nbsp;[&nbsp;insert_at_a(mapVar,strVar,result)&nbsp;];</span></li>



</ol></div>



</div>



</div>
<div>&nbsp;&nbsp;&nbsp; 后面又加了一个<strong>Actor</strong>，把strVar及result放到<strong>map</strong>类型的mapVar中。<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp; 回到factor规则，我们试着把变量名规则的<strong>Actor</strong>写成[factor.val ＝ getvalue(arg1, arg2)]，注意所有字符串规则的<strong>Actor</strong>都会有两个参数，它们是两个迭代器，分别指向起始位置和结束位置。所以这里使用了<strong>phoenix</strong>的arg1和arg2占位符。<br>&nbsp;&nbsp;&nbsp; 这个getvalue我们把它写成一个函数，它从<strong>map</strong>中取出变量名对应的数值。</div>
<div>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt"><span class="datatypes">double&nbsp;getvalue(<span class="keyword">const&nbsp;<span class="datatypes">char*first,&nbsp;<span class="keyword">const&nbsp;<span class="datatypes">char*last)</span></span></span></span></span></li>
<li>{</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return&nbsp;mapVar[string(first,last)];</span></li>
<li>}</li>



</ol></div>













</div>













</div>
<div>&nbsp;&nbsp;&nbsp; 编译，出现错误，说不能把arg1转换成字符串云云。看来这招不行，查<strong>phoenix</strong>手册，手册说想要在<strong>phoenix</strong>的表达式中使用函数，就得按它说的去做-_-<br>&nbsp;&nbsp;&nbsp; 它的要求是这样地：<br>&nbsp;&nbsp;&nbsp; 1.先按如下形式做一个函数对象</div>
<div>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt"><span class="keyword">struct&nbsp;func_impl</span></li>
<li>{</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//Param1等对就的是各个输入参数的类型</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">template&lt;<span class="keyword">typename&nbsp;Param1,<span class="keyword">typename&nbsp;Param2,...,<span class="keyword">typename&nbsp;ParamN&gt;</span></span></span></span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">struct&nbsp;result{</span></li>
<li>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="comment">//定义输出参数的类型</span></li>
<li class="alt">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="keyword">typedef&nbsp;returntype&nbsp;type;</span></li>
<li>&nbsp; &nbsp; };</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//在这里该干啥干啥</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">template&lt;<span class="keyword">typename&nbsp;Param1,<span class="keyword">typename&nbsp;Param2,...,<span class="keyword">typename&nbsp;ParamN&gt;</span></span></span></span></li>
<li class="alt">&nbsp; &nbsp; returntype&nbsp;operator()(...)</li>
<li>&nbsp; &nbsp; {</li>
<li class="alt">&nbsp; &nbsp; &nbsp; &nbsp; ...</li>
<li>&nbsp; &nbsp; }</li>
<li class="alt">};</li>













</ol></div>
<div>&nbsp;</div>













</div>













</div>
<div>&nbsp;&nbsp;&nbsp; 2.使用phoenix::function类来包装第一步做的函数对象，这样才能和<strong>phoenix</strong>配合呢</div>
<div><br>&nbsp;&nbsp;&nbsp; 另外，也可以直接用phoenix::bind把简单函数包装起来使用，不过这样虽然简单很多，在我们这个例子中却不便于封装于是作罢(主要还是想秀一下)。<br>&nbsp;&nbsp;&nbsp; 嗯，动手做吧：</div>
<div>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt"><span class="comment">//适配phoenix的函数对象</span></li>
<li><span class="keyword">struct&nbsp;getvalue_impl</span></li>
<li class="alt">{</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">template&nbsp;&lt;<span class="keyword">typename&nbsp;ParamA,<span class="keyword">typename&nbsp;ParamB&gt;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//输入参数类型</span></span></span></span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">struct&nbsp;result{</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">typedef&nbsp;<span class="datatypes">double&nbsp;type;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//返回类型</span></span></span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};</li>
<li></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//函数主体,其实这里的ParamA和ParamB都是char*</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">template&nbsp;&lt;<span class="keyword">typename&nbsp;ParamA,<span class="keyword">typename&nbsp;ParamB&gt;</span></span></span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="datatypes">double&nbsp;operator()(ParamA&nbsp;<span class="keyword">const&amp;&nbsp;start,ParamB&nbsp;<span class="keyword">const&amp;&nbsp;end)&nbsp;<span class="keyword">const</span></span></span></span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//返回变量名对应的数值</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return&nbsp;m_mapVar[string(start,end)];</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</li>
<li></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;getvalue_impl(map&lt;string,<span class="datatypes">double</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:m_mapVar(mapVar){;}</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">private:</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;map&lt;string,<span class="datatypes">double</span></li>
<li class="alt">};</li>
<li></li>
<li class="alt"><span class="comment">//&nbsp;phoenix表达式中能接受的仿函数类型</span></li>
<li><span class="keyword">const&nbsp;function&lt;getvalue_impl&gt;&nbsp;getValue&nbsp;＝&nbsp;getvalue_impl();</span></li>



</ol></div>













</div>













</div>
<div>&nbsp;&nbsp;&nbsp; 现在终于可以使用了，所有难点已经突破，可以完工了：</div>
<div>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt"><span class="preprocessor">#include&nbsp;&lt;iostream&gt;</span></li>
<li><span class="preprocessor">#include&nbsp;&lt;map&gt;<map></map></span></li>
<li class="alt"><span class="preprocessor">#include&nbsp;&lt;boost/spirit.hpp&gt;</span></li>
<li><span class="preprocessor">#include&nbsp;&lt;boost/spirit/phoenix.hpp&gt;</span></li>
<li class="alt"><span class="preprocessor">#include&nbsp;&lt;boost/spirit/actor.hpp&gt;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;insert_at_a需要</span></li>
<li></li>
<li class="alt"><span class="keyword">using&nbsp;<span class="keyword">namespace&nbsp;std;</span></span></li>
<li><span class="keyword">using&nbsp;<span class="keyword">namespace&nbsp;boost::spirit;</span></span></li>
<li class="alt"><span class="keyword">using&nbsp;<span class="keyword">namespace&nbsp;phoenix;</span></span></li>
<li></li>
<li class="alt"><span class="keyword">struct&nbsp;calc_closure&nbsp;:&nbsp;boost::spirit::closure&lt;calc_closure,&nbsp;<span class="datatypes">double&gt;</span></span></li>
<li>{</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;member1&nbsp;val;</li>
<li>};</li>
<li class="alt"></li>
<li><span class="keyword">struct&nbsp;calculator&nbsp;:&nbsp;<span class="keyword">public&nbsp;grammar&lt;calculator,&nbsp;calc_closure::context_t&gt;</span></span></li>
<li class="alt">{</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">template&nbsp;&lt;<span class="keyword">typename&nbsp;ScannerT&gt;</span></span></li>
<li class="alt">&nbsp; &nbsp; <span class="keyword">struct&nbsp;definition</span></li>
<li>&nbsp; &nbsp; {</li>
<li class="alt">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<span class="keyword">typedef&nbsp;rule&lt;scannert,&nbsp;calc_closure::context_t&gt;&nbsp;rule_type;</span></li>
<li>&nbsp; &nbsp; &nbsp; &nbsp; rule_type&nbsp;factor,&nbsp;term,&nbsp;exp;</li>
<li class="alt"></li>
<li>&nbsp; &nbsp; &nbsp; &nbsp; rule&nbsp;rlStart;</li>
<li class="alt">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<span class="keyword">const&nbsp;rule&amp;&nbsp;start()&nbsp;<span class="keyword">const&nbsp;{&nbsp;<span class="keyword">return&nbsp;rlStart;&nbsp;}</span></span></span></li>
<li></li>
<li class="alt">&nbsp; &nbsp; &nbsp; &nbsp; definition(calculator&nbsp;<span class="keyword">const&amp;&nbsp;self)</span></li>
<li>&nbsp; &nbsp; &nbsp; &nbsp; {</li>
<li class="alt">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; factor&nbsp;=&nbsp;real_p[factor.val&nbsp;=&nbsp;arg1]&nbsp;|</li>
<li>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<span class="comment">//&nbsp;允许在表达式中使用变量，结果用calculator::m_getValue从map中取</span></li>
<li class="alt">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (alpha_p&nbsp;&gt;&gt;&nbsp;*(alnum_p))[&nbsp;factor.val&nbsp;=&nbsp;self.m_getValue(arg1,&nbsp;arg2)&nbsp;]&nbsp;|</li>
<li>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (<span class="string">'('&nbsp;&gt;&gt;&nbsp;exp[factor.val&nbsp;=&nbsp;arg1]&nbsp;&gt;&gt;&nbsp;<span class="string">')');</span></span></li>
<li class="alt">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; term&nbsp;&nbsp;&nbsp;=&nbsp;factor[term.val&nbsp;=&nbsp;arg1]&nbsp;&gt;&gt;</li>
<li>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; *((<span class="string">'*'&nbsp;&gt;&gt;&nbsp;factor[term.val&nbsp;*=&nbsp;arg1])&nbsp;|</span></li>
<li class="alt">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (<span class="string">'/'&nbsp;&gt;&gt;&nbsp;factor[term.val&nbsp;/=&nbsp;arg1]));</span></li>
<li>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; exp&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;term[exp.val&nbsp;=&nbsp;arg1]&nbsp;&gt;&gt;</li>
<li class="alt">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; *((<span class="string">'+'&nbsp;&gt;&gt;&nbsp;term[exp.val&nbsp;+=&nbsp;arg1])&nbsp;|</span></li>
<li>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (<span class="string">'-'&nbsp;&gt;&gt;&nbsp;term[exp.val&nbsp;-=&nbsp;arg1]));</span></li>
<li class="alt">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rlStart&nbsp;&nbsp;=&nbsp;exp[self.val&nbsp;=&nbsp;arg1];&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li>
<li>&nbsp; &nbsp; &nbsp; &nbsp; }</li>
<li class="alt">&nbsp; &nbsp; };</li>
<li></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;calculator(map&lt;string,<span class="datatypes">double</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:m_getValue(&nbsp;getvalue_impl(mapVar)&nbsp;)&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//初始化，把map传给m_getValue</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;{}</li>
<li></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//适配phoenix的函数对象</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">struct&nbsp;getvalue_impl</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;{</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">template&nbsp;&lt;<span class="keyword">typename&nbsp;ParamA,<span class="keyword">typename&nbsp;ParamB&gt;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//输入参数类型</span></span></span></span></li>
<li class="alt">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<span class="keyword">struct&nbsp;result{</span></li>
<li>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<span class="keyword">typedef&nbsp;<span class="datatypes">double&nbsp;type;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//返回类型</span></span></span></li>
<li class="alt">&nbsp; &nbsp; &nbsp; &nbsp; };</li>
<li></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//函数主体,其实这里的ParamA和ParamB都是char*</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">template&nbsp;&lt;<span class="keyword">typename&nbsp;ParamA,<span class="keyword">typename&nbsp;ParamB&gt;</span></span></span></li>
<li class="alt">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<span class="datatypes">double&nbsp;operator()(ParamA&nbsp;<span class="keyword">const&amp;&nbsp;start,ParamB&nbsp;<span class="keyword">const&amp;&nbsp;end)&nbsp;<span class="keyword">const</span></span></span></span></li>
<li>&nbsp; &nbsp; &nbsp; &nbsp; {</li>
<li class="alt">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<span class="comment">//返回变量名对应的数值</span></li>
<li>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<span class="keyword">return&nbsp;m_mapVar[string(start,end)];</span></li>
<li class="alt">&nbsp; &nbsp; &nbsp; &nbsp; }</li>
<li></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getvalue_impl(map&lt;string,<span class="datatypes">double</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:m_mapVar(mapVar){;}</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">private:</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;map&lt;string,<span class="datatypes">double</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;};</li>
<li></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;phoenix表达式中能接受的仿函数类型</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">const&nbsp;function&lt;getvalue_impl&gt;&nbsp;m_getValue;</span></li>
<li class="alt">};</li>
<li></li>
<li class="alt"><span class="comment">//用来显示map中变量的值</span></li>
<li><span class="keyword">void&nbsp;showPair(<span class="keyword">const&nbsp;pair&lt;string,&lt; span=""&gt;<span class="datatypes">double&gt;&nbsp;&amp;val)</span></span></span></li>
<li class="alt">{</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;val.first&nbsp;&lt;&lt;&nbsp;<span class="string">"&nbsp;=&nbsp;"&nbsp;&lt;&lt;&nbsp;val.second&nbsp;&lt;&lt;&nbsp;endl;</span></li>
<li class="alt">}</li>
<li></li>
<li class="alt"><span class="datatypes">int&nbsp;main()</span></li>
<li>{</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;string&nbsp;strVar;</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<span class="datatypes">double&nbsp;result;</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//用来保存变量和对应的数值</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;map&lt;string,<span class="datatypes">double</span></li>
<li class="alt"></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//把map传给语法类，让解析器知道变量的值</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;calculator&nbsp;calc(mapVar);</li>
<li></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;变量名规则(alpha_p&nbsp;&gt;&gt;&nbsp;+(alnum_p))，除第一位外后面可以跟数字。</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;整个等式末尾加入insert_at_a的actor，匹配成功后把变量和数值存到map中。</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;rule&lt;phrase_scanner_t&gt;&nbsp;rlEqu&nbsp;=</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(alpha_p&nbsp;&gt;&gt;&nbsp;*(alnum_p))[assign(strVar)]&nbsp;&gt;&gt;</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="string">'='&nbsp;&gt;&gt;&nbsp;calc[assign_a(result)]&nbsp;)&nbsp;[&nbsp;insert_at_a(mapVar,strVar,result)&nbsp;];</span></li>
<li class="alt"></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;多行赋值语句，表达式用使用变量</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">const&nbsp;<span class="datatypes">char&nbsp;*szEqus[3]&nbsp;=&nbsp;{</span></span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="string">"PI&nbsp;=&nbsp;3.1415926",</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="string">"Rad&nbsp;=&nbsp;PI*2.0/3.0",</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="string">"Deg&nbsp;=&nbsp;Rad*180/PI"};</span></li>
<li class="alt"></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;逐句解析</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for(<span class="datatypes">int&nbsp;i=0;&nbsp;i&lt;3;&nbsp;i++)&nbsp;&nbsp;&nbsp;&nbsp;parse(szEqus[i],&nbsp;rlEqu,&nbsp;space_p);</span></span></li>
<li></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;显示每个变量的数值</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;for_each(mapVar.begin(),&nbsp;mapVar.end(),&nbsp;showPair&nbsp;);</li>
<li class="alt"></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return&nbsp;0;</span></li>
<li class="alt">}</li>



</ol></div>













</div>













</div>
<div>显示结果：</div>













&nbsp;&nbsp;&nbsp; Deg = 120 &nbsp;&nbsp;&nbsp; PI = 2.14159 &nbsp;&nbsp;&nbsp; Rad = 2.0944
<div>到现在，我们已经可以向别人吹嘘说：脚本解析？小菜！！！哈哈...</div>
<div>&nbsp;</div>
<div>持续改进...&nbsp;&nbsp;&nbsp;&nbsp;<span style="text-decoration: underline;">例五</span>的代码用起来很爽吧，不算注释的话100行不到，已经有个脚本的雏形了。只是...只是有个小问题，因为我们设置了跳过空格，这对于语句来说是必须的，但却带来了一个副作用。<br>&nbsp;&nbsp;&nbsp; 试试把szEqus里的变量名中间加个空格，比如改成"R ad = P&nbsp;&nbsp; I*2.0/3.0"，这样的语句居然也能正确解析，这显然不是我们想要的（要的就是这种效果？！！偶无语...）。<br>&nbsp;&nbsp;&nbsp; 那么怎样才能解析变量名时不许跳过空格，而解析语句的又允许跳过呢(搞双重标准)？下面介绍的命令就可以帮上忙了，首先赶快在没人发现这个错误之前把它搞定先：<br>&nbsp;&nbsp;&nbsp; 把所有的<strong>变量名规则</strong>（factor规则定义里有一个，rlEqu规则定义里有一个）用<strong>lexeme_d</strong>包裹起来：<br>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt">lexeme_d[(alpha_p&nbsp;&gt;&gt;&nbsp;*(alnum_p))]</li>



</ol></div>













</div>













&nbsp;&nbsp;&nbsp; 再测试，嗯，现在不允许出现含有空格的变量名了。<br>下面介绍各种预置命令&nbsp;&nbsp;&nbsp; 使用形式:&nbsp;<strong>命令</strong>[解析器表达式]<br>&nbsp;&nbsp;&nbsp;&nbsp;<strong>lexeme_d</strong><br>&nbsp;&nbsp;&nbsp; 不跳过空白字符，当工作于语法级时，解析器会忽略空白字符，lexeme_d使其临时工作于字符级<br>&nbsp;&nbsp;&nbsp; 如整数定义应该是:&nbsp;integer = lexeme_d[ !(ch_p('+') | '-') &gt;&gt; +digit ];，这样可以防止"1 2 345"被解析为"12345"<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<strong>as_lower_d</strong><br>&nbsp;&nbsp;&nbsp; 忽略大小写，解析器默认是大小写敏感的，如果要解析象<strong>PASCAL</strong>一样的大小写不敏感的语法，使用r = as_lower_d["begin"];(注，里面的参数都得小写)<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<strong>no_actions_d</strong><br>&nbsp;&nbsp;&nbsp; 停止触发<strong>Actor</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<strong>longest_d</strong><br>&nbsp;&nbsp;&nbsp; 尝试最长匹配<br>&nbsp;&nbsp;&nbsp; 如number = integer | real;用它匹配123.456时，integer会匹配123直到遇到小数点结束，使用number=longest_d[integer | real];可以避免这个问题。<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<strong>shortest_d</strong><br>&nbsp;&nbsp;&nbsp; 与<strong>longest_d</strong>相反<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<strong>limit_d</strong><br>&nbsp;&nbsp;&nbsp; 定义范围,用法<strong>limit_d</strong>(min, max)[expression]<br>&nbsp;&nbsp;&nbsp; 如<br>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt">uint_parser&lt;<span class="datatypes">int,&nbsp;10,&nbsp;2,&nbsp;2&gt;&nbsp;uint2_p;</span></li>
<li>r&nbsp;=&nbsp;lexeme_d</li>
<li class="alt">[</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;limit_d(0u,&nbsp;23u)[uint2_p]&nbsp;&gt;&gt;&nbsp;<span class="string">':'&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;&nbsp;Hours&nbsp;00..23</span></span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&gt;&gt;&nbsp;&nbsp;limit_d(0u,&nbsp;59u)[uint2_p]&nbsp;&gt;&gt;&nbsp;<span class="string">':'&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;&nbsp;Minutes&nbsp;00..59</span></span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&gt;&gt;&nbsp;&nbsp;limit_d(0u,&nbsp;59u)[uint2_p]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;&nbsp;Seconds&nbsp;00..59</span></li>
<li class="alt">];</li>



</ol></div>



</div>



&nbsp;&nbsp;&nbsp;&nbsp;<strong>min_limit_d/max_limit_d</strong><br>&nbsp;&nbsp;&nbsp; 定义最小/最大值，用法:<strong>min_limit_d</strong>(min)[expression]<br>例七，牛叉型解析器&nbsp;&nbsp;&nbsp; 相对于<strong>Spirit</strong>预置的一些<strong>简单解析器</strong>，它也提供了很多功能更强大的“牛叉型”解析器。现介绍如下：<br>&nbsp;&nbsp;&nbsp;<strong>&nbsp;f_ch_p</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 语法：f_ch_p(ChGenT&nbsp;chgen)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 作用：和<strong>ch_p</strong>类似，它解析的字符由chgen的返回值决定，chgen是一个类型为"CharT&nbsp;func()"的函数（或函数对象）<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 例如：char&nbsp;X(){return&nbsp;'X';}&nbsp;<strong>f_ch_p</strong>(&amp;X);&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<strong>f_range_p</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 语法：f_range_p(ChGenAT&nbsp;first, ChGenBT&nbsp;last)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 作用：和<strong>range_p</strong>类似，它由first和last两个函数（或函数对象）的返回值决定解析的字符范围。<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<strong>f_chseq_p</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 语法：f_chseq_p(IterGenAT&nbsp;first, IterGenBT&nbsp;last)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 作用：和<strong>chseq_p</strong>类似，同样由first和last两个函数（或函数对象）的返回值决定起始和终止迭代器。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<strong>f_str_p</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 语法：f_str_p(IterGenAT&nbsp;first, IterGenBT&nbsp;last)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 作用：和<strong>str_p</strong>类似，参数同<strong>f_chseq_p</strong>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<strong>if_p</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 语法：if_p(condition)[then-parser].else_p[else-parser]，其中.else_p可以不要<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 作用：如果condition成立，就使用then-parser,否则用else-parset<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 例如：<strong>if_p</strong>("0x")[hex_p]<strong>.else_p</strong>[uint_p]<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;<strong>&nbsp;for_p</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 语法：for_p(init, condition, step)[body-parser]<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 作用：init和step是一个无参数的函数或函数对象，各参数与for的作用类似（先init,再检查condition,有效则执行body-parser及step,再检查condition...)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 例如：<strong>for_p</strong>(var(i)=0,&nbsp;var(i) &lt; 10, ++var(i) ) [&nbsp;int_p[var(sum) += arg1] ]<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<strong>while_p, do_p</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 语法：while_p(condition)[body-parser] 及 do_p[body-parser].while_p(condition)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 作用：条件循环，直接condition不成立为止。<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<strong>select_p, select_fail_p</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 语法：select_p(parser_a , parser_b /* ... */, parser_n);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 作用：从左到右接顺序测试各解析器，并得到匹配的解析器的序号（0表示匹配parser_a,1匹配parser_b...）<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 例如：见<strong>switch_p</strong>例<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<strong>switch_p</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 语法：switch_p(value)[case_p&lt;value_a&gt;(parser_a),case_p&lt;value_b&gt;(parser_b),...,default_p(parser_def)]<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 作用：按value的值选择<strong>解析器</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 例如：下例中匹配的形式为:字符a后是整数，b后是个逗号,c后跟着"bcd"，d后什么也没有。<br>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt"><span class="datatypes">int&nbsp;choice&nbsp;=&nbsp;-1;</span></li>
<li>rule&lt;&gt;&nbsp;rule_select&nbsp;=</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;select_fail_p(<span class="string">'a',&nbsp;<span class="string">'b',&nbsp;<span class="string">'c',&nbsp;<span class="string">'d')[assign_a(choice)]</span></span></span></span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&gt;&gt;&nbsp;switch_p(var(choice))</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case_p&lt;0&gt;(int_p),</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case_p&lt;1&gt;(ch_p(<span class="string">',')),</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case_p&lt;2&gt;(str_p(<span class="string">"bcd")),</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;default_p</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;];</li>



</ol></div>



</div>



&nbsp;&nbsp;&nbsp;<strong>&nbsp;c_escape_ch_p, lex_escape_ch_p</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 语法：c_escape_ch_p<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 作用：和<strong>ch_p</strong>类似，其牛叉的地方在于能<strong>解析C语言里的转义字符</strong>：\b, \t, , \f, , \\, \", \', \xHH, \OOO<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 例如：confix_p('"', *<strong>c_escape_ch_p</strong>, '"')<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<strong>repeat_p</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 语法、作用：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; repeat_p (n) [p]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 重复n次执行解析器p&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; repeat_p (n1, n2) [p]&nbsp;&nbsp; 重复n1到n2次解析器p&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; repeat_p (n, more) [p]&nbsp; 至少重复n次解析&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 例如：检验是否是有效的文件名<br>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt">valid_fname_chars&nbsp;=&nbsp;<span class="comment">/*..*/;</span></li>
<li>filename&nbsp;=&nbsp;repeat_p(1,&nbsp;255)[valid_fname_chars];</li>



</ol></div>



</div>



&nbsp;&nbsp;&nbsp;&nbsp;<strong>confix_p</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 语法：confix_p(open,expr,close)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 作用：解析独立元素，如C语言里的字符串，注释等，相当于open &gt;&gt; (expr - close) &gt;&gt; close<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 例如：解析C注释<strong>confix_p</strong>("/*", *anychar_p, "*/")<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<strong>comment_p,comment_nest_p</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 语法：comment_p(open,close),如果close不指定，默认为回车<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 作用：confix_p的辅助解析器，<strong>comment_p</strong>遇到第一个close时即返回，而<strong>comment_nest_p</strong>要open/close对匹配才返回。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 例如：<br>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt">comment_p(<span class="string">"//")&nbsp;C++风格注释</span></li>
<li>comment_nest_p(<span class="string">'{',&nbsp;<span class="string">'}')|comment_nest_p(<span class="string">"(*",&nbsp;<span class="string">"*)")&nbsp;pascal风格注释</span></span></span></span></li>



</ol></div>



</div>



&nbsp;&nbsp;&nbsp;&nbsp;<strong>list_p</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 语法：list_p(paser,delimiter)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 作用：匹配以delimiter作为分隔符的列表<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<strong>regex_p</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 语法：regex_p("正则表达式")<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 作用：使用<a href="http://www.cppprog.com/2009/0116/53.html">正则表达式</a>来匹配字符串(强强联手啊~~啥也不说了)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<strong>symbols类</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 定义：
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt"><span class="keyword">template</span></li>
<li>&lt;</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">typename&nbsp;T&nbsp;=&nbsp;<span class="datatypes">int,</span></span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">typename&nbsp;CharT&nbsp;=&nbsp;<span class="datatypes">char,</span></span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">typename&nbsp;SetT&nbsp;=&nbsp;impl::tst&lt;t,&nbsp;chart&gt;</span></li>
<li>&gt;</li>
<li class="alt"><span class="keyword">class&nbsp;symbols;</span></li>



</ol></div>













</div>













&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 初始化方式：
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt">symbols&lt;&gt;&nbsp;sym;</li>
<li>sym&nbsp;=&nbsp;<span class="string">"pineapple",&nbsp;<span class="string">"orange",&nbsp;<span class="string">"banana",&nbsp;<span class="string">"apple",&nbsp;<span class="string">"mango";</span></span></span></span></span></li>
<li class="alt">sym.add(<span class="string">"hello",&nbsp;1)(<span class="string">"crazy",&nbsp;2)(<span class="string">"world",&nbsp;3);</span></span></span></li>



</ol></div>













</div>













&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 作用：匹配字符串(CharT*)返回对应的整数(T)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 例如：<br>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt"><span class="keyword">struct&nbsp;Show{</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">void&nbsp;operator()(&nbsp;<span class="datatypes">int&nbsp;n&nbsp;)&nbsp;<span class="keyword">const</span></span></span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;{</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;n;</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;}</li>
<li>};</li>
<li class="alt">symbols&lt;&gt;&nbsp;sym;</li>
<li>sym.add(<span class="string">"零",0)&nbsp;</span>(<span class="string">"一",1)&nbsp;(<span class="string">"二",2)&nbsp;(<span class="string">"三",3)&nbsp;</span></span></span>(<span class="string">"四",4)&nbsp;(<span class="string">"五",5)&nbsp;(<span class="string">"六",6)&nbsp;</span></span></span>(<span class="string">"七",7) (<span class="string">"八",8) (<span class="string">"九",9);</span></span></span></li>
<li>parse(<span class="string">"二零零八",*(sym[Show()]));&nbsp;</span></li>



</ol></div>



</div>



&nbsp;&nbsp;&nbsp;&nbsp;<strong>functor_parser</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 作用：可以方便地用它来创建一个<strong>解析器</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 例如：见下例<br>演示怎样自己写一个解析器，解析一个整数
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt"><span class="keyword">struct&nbsp;number_parser</span></li>
<li>{</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">typedef&nbsp;<span class="datatypes">int&nbsp;result_t;&nbsp;&nbsp;&nbsp;<span class="comment">//定义解析器结果类型</span></span></span></li>
<li></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//参数是:扫描器，结果</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">template&nbsp;&lt;<span class="keyword">typename&nbsp;ScannerT&gt;</span></span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;std::<span class="datatypes">ptrdiff_t&nbsp;operator()(ScannerT&nbsp;<span class="keyword">const&amp;&nbsp;scan,&nbsp;result_t&amp;&nbsp;result)&nbsp;<span class="keyword">const</span></span></span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;{</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if&nbsp;(scan.at_end())&nbsp;&nbsp;<span class="comment">//如果结果或出错，返回-1</span></span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return&nbsp;-1;</span></li>
<li class="alt"></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="datatypes">char&nbsp;ch&nbsp;=&nbsp;*scan;</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if&nbsp;(ch&nbsp;&lt;&nbsp;<span class="string">'0'&nbsp;||&nbsp;ch&nbsp;&gt;&nbsp;<span class="string">'9')</span></span></span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return&nbsp;-1;</span></li>
<li class="alt"></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result&nbsp;=&nbsp;0;</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::<span class="datatypes">ptrdiff_t&nbsp;len&nbsp;=&nbsp;0;</span></li>
<li></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">do&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//解析字符串，得到结果</span></span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result&nbsp;=&nbsp;result*10&nbsp;+&nbsp;<span class="datatypes">int(ch&nbsp;-&nbsp;<span class="string">'0');&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;++len;</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;++scan;</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span class="keyword">while&nbsp;(!scan.at_end()&nbsp;&amp;&amp;&nbsp;(ch&nbsp;=&nbsp;*scan,&nbsp;ch&nbsp;&gt;=&nbsp;<span class="string">'0'&nbsp;&amp;&amp;&nbsp;ch&nbsp;&lt;=&nbsp;<span class="string">'9'));</span></span></span></li>
<li class="alt"></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return&nbsp;len;&nbsp;<span class="comment">//返回解析的字符串长度</span></span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;}</li>
<li>};</li>
<li class="alt"><span class="comment">//用functor_parser包装成解析器</span></li>
<li>functor_parser&lt;number_parser&gt;&nbsp;number_parser_p;</li>













</ol></div>













</div>













</div>
<div><em>例八，抽象语法树(abstract syntax tree，简称AST)</em></div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>&nbsp; &nbsp; 上面的例子都是<strong>就地解析</strong>。在比较大型的语法解析中，一种更通用的方式是先产生<strong>抽象语法树</strong>再遍历它来做解析工作。比如著名的GCC，观察它的源代码就可以发现，它解析源代码时首先生成AST再开始编译。其它编译器因为看不到源码不好说，想来也该是如此吧。<br>&nbsp;&nbsp;&nbsp; Spirit也支持生成<strong>抽象语法树</strong>的功能（不过用它来解析C++代码可就不太合适了，Spirit针对的是轻量的小型脚本）</div>
<div><br>&nbsp;&nbsp;&nbsp; 头文件<br>&nbsp; &nbsp; #include&nbsp;&lt;boost/spirit/include/classic_ast.hpp&gt;</div>
<div><br>&nbsp;&nbsp;&nbsp; 使用<strong>AST</strong>和之前的解析步骤很相似，一个重要的区别是所有的子规则都应该是<strong>字符串形式</strong>的，也就是说real_p,int_p之类的帮不上忙了，我们得自力更生。<br>&nbsp;&nbsp;&nbsp; 我们在<a href="http://www.cppprog.com/2009/0121/55.html">例一</a>中使用过的浮点数解析器这次可以派上用场了。&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp; 下面的例子参考了<a href="http://www.cppprog.com/2009/0122/56.html">例四</a>中的解析器规则：<br>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt"><span class="preprocessor">#include&nbsp;&lt;iostream&gt;</span></li>
<li><span class="preprocessor">#include&nbsp;&lt;boost/spirit.hpp&gt;</span></li>
<li class="alt"><span class="preprocessor">#include&nbsp;&lt;boost/spirit/include/classic_ast.hpp&gt;</span></li>
<li></li>
<li class="alt"><span class="keyword">using&nbsp;<span class="keyword">namespace&nbsp;std;</span></span></li>
<li><span class="keyword">using&nbsp;<span class="keyword">namespace&nbsp;boost::spirit;</span></span></li>
<li class="alt"></li>
<li><span class="keyword">struct&nbsp;calculator&nbsp;:&nbsp;<span class="keyword">public&nbsp;grammar</span></span></li>
<li class="alt">{</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">template&nbsp;&lt;<span class="keyword">typename&nbsp;ScannerT&gt;</span></span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">struct&nbsp;definition</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;{</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">typedef&nbsp;rule&nbsp;rule_type;</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rule_type&nbsp;factor,&nbsp;term,&nbsp;exp,&nbsp;str_real_p;</li>
<li class="alt"></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">const&nbsp;rule_type&amp;&nbsp;start()&nbsp;<span class="keyword">const&nbsp;{&nbsp;<span class="keyword">return&nbsp;exp;&nbsp;}</span></span></span></li>
<li class="alt"></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;definition(calculator&nbsp;<span class="keyword">const&amp;&nbsp;self)</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;str_real_p&nbsp;=&nbsp;leaf_node_d[</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;!(ch_p(<span class="string">'+')|<span class="string">'-')&gt;&gt;+digit_p&gt;&gt;</span></span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;!(<span class="string">'.'&gt;&gt;+digit_p)&gt;&gt;!((ch_p(<span class="string">'e')|<span class="string">'E')&nbsp;&gt;&gt;</span></span></span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;!(ch_p(<span class="string">'+')|<span class="string">'-')&gt;&gt;+digit_p)</span></span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;];</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;factor&nbsp;=&nbsp;str_real_p&nbsp;|&nbsp;inner_node_d[(<span class="string">'('&nbsp;&gt;&gt;&nbsp;exp&nbsp;&gt;&gt;&nbsp;<span class="string">')')];</span></span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;term&nbsp;&nbsp;&nbsp;=&nbsp;factor&nbsp;&gt;&gt;&nbsp;*((root_node_d[ch_p(<span class="string">'*')]&nbsp;&gt;&gt;&nbsp;factor)</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;(root_node_d[ch_p(<span class="string">'/')]&nbsp;&gt;&gt;&nbsp;factor));</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exp&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;term&nbsp;&gt;&gt;&nbsp;*((root_node_d[ch_p(<span class="string">'+')]&nbsp;&gt;&gt;&nbsp;term)</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;(root_node_d[ch_p(<span class="string">'-')]&nbsp;&gt;&gt;&nbsp;term));</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;};</li>
<li>};</li>
<li class="alt"></li>
<li><span class="comment">//显示AST的结构,Indent是缩进宽度</span></li>
<li class="alt"><span class="keyword">typedef&nbsp;tree_match&lt;<span class="datatypes">char&nbsp;<span class="keyword">const*&gt;::container_t&nbsp;container_t;</span></span></span></li>
<li><span class="keyword">void&nbsp;showTree(<span class="keyword">const&nbsp;container_t&amp;&nbsp;con,&nbsp;<span class="datatypes">int&nbsp;Indent)</span></span></span></li>
<li class="alt">{</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for(container_t::const_iterator&nbsp;itr=con.begin();&nbsp;itr!=con.end();&nbsp;++itr)</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;{</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//tree_node:&nbsp;value,&nbsp;children</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//显示当前值</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;string(Indent*4,&nbsp;<span class="string">'&nbsp;')&nbsp;&lt;&lt;&nbsp;<span class="string">"|--("&nbsp;&lt;&lt;</span></span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string(itr-&gt;value.begin(),&nbsp;itr-&gt;value.end())&nbsp;&lt;&lt;&nbsp;<span class="string">')'&nbsp;&lt;&lt;&nbsp;endl;</span></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//显示子节点</span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;showTree(itr-&gt;children,&nbsp;Indent+1);</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;}</li>
<li class="alt">}</li>
<li></li>
<li class="alt"><span class="datatypes">int&nbsp;main()</span></li>
<li>{</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;calculator&nbsp;calc;</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">const&nbsp;<span class="datatypes">char&nbsp;*szExq&nbsp;=&nbsp;<span class="string">"12&nbsp;*&nbsp;(24&nbsp;-&nbsp;15)&nbsp;/&nbsp;(17&nbsp;+&nbsp;6)";</span></span></span></li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;tree_parse_info&lt;&gt;&nbsp;info&nbsp;=&nbsp;ast_parse(szExq,&nbsp;calc,&nbsp;space_p);</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;showTree(info.trees,&nbsp;0);</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return&nbsp;0;</span></li>
<li>}</li>



</ol></div>



</div>



&nbsp;&nbsp;&nbsp; 这个程序可以显示出整个<strong>AST</strong>的结构，比如例子中的“12 * (24 - 15) / (17 + 6)”, 解析结果(用图片美化了一下):</div>
<div><br>









&nbsp;&nbsp;&nbsp;&nbsp;<img src="./Boost学习之语法解析器--Spirit - xueyoo - 博客园_files/321507-20150929181619652-1394524355.gif" alt=""><br>&nbsp;&nbsp;&nbsp; 这个代码和之前的代码主要区别是多了几个<strong>xxxx_node_d</strong>形式的命令，以及使用<strong>ast_parse</strong>函数来解析。 tree_parse_info类型&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>ast_parse</strong>的参数与<strong>parse</strong>相同，主要区别就在于它的返回值不是parse_info而是tree_parse_info。<br>&nbsp;&nbsp;&nbsp;&nbsp;tree_parse_info的成员有：<br>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt">IteratorT&nbsp;&nbsp;&nbsp;stop;</li>
<li><span class="datatypes">bool&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;match;</span></li>
<li class="alt"><span class="datatypes">bool&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;full;</span></li>
<li>std::<span class="datatypes">size_t&nbsp;length;</span></li>
<li class="alt"><span class="keyword">typename&nbsp;tree_match&lt;IteratorT, NodeFactoryT, T&gt;::container_t&nbsp;trees;</span></li>



</ol></div>



</div>



&nbsp;&nbsp;&nbsp; 前四个和parse_info相同，多出来的trees是一个含有tree_node的容器（默认的容器是std::vector，如果预定义了BOOST_SPIRIT_USE_LIST_FOR_TREES，就会使用std::list）<br>&nbsp;&nbsp;&nbsp;&nbsp;tree_node有两个重要的成员：
<ul>
<li><strong>children</strong>:&nbsp;&nbsp; 子节点，与tree_parse_info里的trees类型相同：std::vector&lt;<strong>tree_node&lt;T&gt;</strong>&gt;(或std::list&lt;...&gt;)</li>
<li><em id="__mceDel"><strong>value</strong>:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 数据，类型为模板T,这个参数默认类型是node_val_data&lt;IteratorT, ValueT&gt;</em></li>













</ul>













&nbsp;&nbsp;&nbsp; 整个<strong>AST</strong>就是由tree_node的数据<strong>value</strong>以及子节点<strong>children</strong>组成的。（参考例子中showTree的代码就可以看出）<br><br>&nbsp;&nbsp;&nbsp;&nbsp;node_val_data&lt;IteratorT, ValueT&gt;的模板参数IteratorT默认是const char*,&nbsp;ValueT是nil_t（空数据，定义为<strong>struct&nbsp;</strong>nil_t&nbsp;{};）。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在这个类内部维护着一个vector(或list)，它保存着解析出来的脚本字符串，比如上面例子中的"12","*","24"等。node_val_data向外提供的重要方法有：
<ul>
<li><strong>begin()/end()</strong>:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 直接返回内部vector(或list)的begin()和end()</li>
<li><strong>is_root()/is_root(bool)</strong>:&nbsp;&nbsp;&nbsp; 取得/设置对应节点的root状态（由root_node_d命令设置）</li>
<li><strong>value()/value(const&nbsp;ValueT&amp;)</strong>取得/设置用户自定义数值（默认的nil_t没法带数据，必须通过指定NodeFactoryT来改变ValueT类型，马上会讲到）</li>
<li><strong>id()/id(parser_id)</strong>:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 取得/设置解析此节点的解析器id(还记得rule的TagT策略吗，下面还会讲到)</li>



</ul>



&nbsp;&nbsp;&nbsp; 它的<strong>value</strong>()方法可以设置和取得自定义数据，不过默认的nil_t却是个空结构，根本不能使用。这时我们可以通过指定“<strong>工厂类</strong>”来改变ValueT的类型，方法如下(假设使用<strong>double</strong>)：<br>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt"><span class="keyword">typedef&nbsp;node_val_data_factory&lt;<span class="datatypes">double&gt;&nbsp;factory_t;</span></span></li>
<li>my_grammar&nbsp;gram;</li>
<li class="alt">my_skip_grammar&nbsp;skip;</li>
<li>tree_parse_info&lt;iterator_t,&nbsp;factory_t&gt;&nbsp;i&nbsp;=</li>
<li class="alt">&nbsp;&nbsp;&nbsp;&nbsp;ast_parse&lt;factory_t&gt;(first,&nbsp;last,&nbsp;gram,&nbsp;skip);</li>



</ol></div>



</div>



&nbsp;&nbsp;&nbsp;&nbsp;<strong>rule</strong>有一个<strong>id()</strong>方法可以返回一个parser_id类型的标记,用它可以区分各个不同的<strong>rule</strong>,它返回什么值由TagT模板参数决定，默认的parser_address_tag返回的是<strong>rule</strong>的内存地址。<br>&nbsp;&nbsp;&nbsp; 我们可以用其它参数代替它以实现更适用的标记，<strong>Spirit</strong>已准备好的TagT策略有:<br>&nbsp;&nbsp;&nbsp;&nbsp;<strong>parser_tag&lt;N&gt;</strong>,它接收一个整数，如<br>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt">rule&lt;parser_tag&nbsp;&gt;&nbsp;my_rule;</li>
<li>assign(rule.id().to_long()&nbsp;==&nbsp;123);</li>
</ol></div>
</div>
&nbsp;&nbsp;&nbsp;&nbsp;<strong>dynamic_parser_tag</strong>, 它给<strong>rule</strong>加入了<strong>set_id(int)</strong>的能力，如:<br>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt">rule&lt;dynamic_parser_tag&gt;&nbsp;my_dynrule;</li>
<li>my_dynrule.set_id(1234);&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;set&nbsp;my_dynrule's&nbsp;id&nbsp;to&nbsp;1234</span></li>
</ol></div>
</div>
&nbsp;&nbsp;&nbsp; 利用这些TagT策略再和node_val_data里的<strong>id()</strong>相比较就能知道这个数据是由哪个<strong>解析器</strong>解析的。<br>下面介绍Spirit为AST而引入的几个命令：&nbsp;&nbsp;&nbsp;&nbsp;<strong>leaf_node_d</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 由leaf_node_d命令包裹的规则将被视为一个整体，它还由另一个名字<strong>token_node_d</strong>。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 尝试把上例中的leaf_node_d命令去掉，再看解析结果：所有的数字都被折成了一个个字节。<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<strong>inner_node_d</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这个命令会忽略第一个子规则和最后一个子规则，只取中间部分。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 把上例中的inner_node_d去掉，那么括号也被参与解析。<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<strong>root_node_d</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这个命令对于<strong>AST</strong>至关重要，由root_node_d命令包裹的节点将成为<strong>同一规则中其它节点的父节点</strong>。它的工作方式如下：<br>假设A是前一节点 B是新产生的节点 如果B是根节点 A成为B的第一个子节点 否则，如果A是根节点而B不是，那么 B成为A的最后一个子节点 其它情况 A和B处于同一级<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 比如这个例子中的“12 * (24 - 15) / (17 + 6)”<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 对于解析器解析顺序是:<br>exp = term term = 12{factor} *{root} (24 - 15){exp} /{root} (17 + 6){exp} ...<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 首先解析<strong>12,</strong>&nbsp;然后是&nbsp;<strong>*</strong>, 这时发现<strong>*</strong>是root，于是<strong>12</strong>成为<strong>*</strong>的第一个子节点<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 接着解析<strong>(24 - 15)</strong>这个exp，同理，<strong>24</strong>成为<strong>-</strong>的第一个子节点，然后是<strong>15</strong>，它不是root，而前一个是，于是<strong>15</strong>成为<strong>-</strong>的最后一个子节点。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 因为<strong>(24 - 15)</strong>这个exp不是root，同样成为了<strong>*</strong>的最后一个子节点。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 再解析<strong>/</strong>，是root, 于是把前一节点（是<strong>*</strong>哦，因为其它的都成了<strong>*</strong>的子节点）变成了它的首个子节点。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 最后解析<strong>(17+6)</strong>这个exp,最终成为了<strong>/</strong>的最后一个子节点。<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<strong>no_node_d</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 忽略由它包裹的规则，比如例子中的:<br>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt">factor&nbsp;=&nbsp;str_real_p&nbsp;|&nbsp;inner_node_d[(<span class="string">'('&nbsp;&gt;&gt;&nbsp;exp&nbsp;&gt;&gt;&nbsp;<span class="string">')')];</span></span></li>













</ol></div>













</div>













&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 也可以这样表示:<br>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt">factor&nbsp;=&nbsp;str_real_p&nbsp;|&nbsp;(no_node_d[ch_p(<span class="string">'(')]&nbsp;&gt;&gt;&nbsp;exp&nbsp;&gt;&gt;&nbsp;no_node_d[ch_p(<span class="string">')')]);</span></span></li>
</ol></div>
</div>
&nbsp;&nbsp;&nbsp;&nbsp;<strong>infix_node_d</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这个命令会删除其规则匹配出的所有节点中偶数位置上的节点，比如：<br>
<div class="HighLighter">
<div class="dp-highlighter"><ol class="dp-cpp">
<li class="alt">rule_t&nbsp;intlist&nbsp;=&nbsp;infix_node_d[&nbsp;integer&nbsp;&gt;&gt;&nbsp;*(<span class="string">','&nbsp;&gt;&gt;&nbsp;integer)&nbsp;];</span></li>













</ol></div>













</div>













&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这条规则将只产生整数数组，偶数位置上的逗号将被删除。<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<strong>discard_first_node_d/discard_last_node_d</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 忽略第一个/最后一个子规则(半个<strong>inner_node_d</strong>功能)<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>我们的Spirit学习先到这里，这些只不过是Spirit里的冰山一角，要发挥Spirit的强大威力，还得继续前进...<br>在/libs/spirit/example里有不少“很好很强大”的例子，比如：小型的C语言解释器，XML解释器等，大家有兴趣可以去研究研究。</div>












</div></div><div id="MySignature"></div>
<div class="clear"></div>
<div id="blog_post_info_block">
<div id="BlogPostCategory">分类: <a href="http://www.cnblogs.com/xueyoo/category/735670.html" target="_blank">C/C++</a></div>
<div id="EntryTag"></div>
<div id="blog_post_info"><div id="green_channel">
        <a href="javascript:void(0);" id="green_channel_digg" onclick="DiggIt(4815448,cb_blogId,1);green_channel_success(this,&#39;谢谢推荐！&#39;);">好文要顶</a>
            <a id="green_channel_follow" onclick="follow(&#39;4af65c58-15bf-e011-8673-842b2b196315&#39;);" href="javascript:void(0);">关注我</a>
    <a id="green_channel_favorite" onclick="AddToWz(cb_entryId);return false;" href="javascript:void(0);">收藏该文</a>
    <a id="green_channel_weibo" href="javascript:void(0);" title="分享至新浪微博" onclick="ShareToTsina()"><img src="./Boost学习之语法解析器--Spirit - xueyoo - 博客园_files/icon_weibo_24.png" alt=""></a>
    <a id="green_channel_wechat" href="javascript:void(0);" title="分享至微信" onclick="shareOnWechat()"><img src="./Boost学习之语法解析器--Spirit - xueyoo - 博客园_files/wechat.png" alt=""></a>
</div>
<div id="author_profile">
    <div id="author_profile_info" class="author_profile_info">
            <a href="http://home.cnblogs.com/u/xueyoo/" target="_blank"><img src="./Boost学习之语法解析器--Spirit - xueyoo - 博客园_files/sample_face.gif" class="author_avatar" alt=""></a>
        <div id="author_profile_detail" class="author_profile_info">
            <a href="http://home.cnblogs.com/u/xueyoo/">xueyoo</a><br>
            <a href="http://home.cnblogs.com/u/xueyoo/followees">关注 - 0</a><br>
            <a href="http://home.cnblogs.com/u/xueyoo/followers">粉丝 - 1</a>
        </div>
    </div>
    <div class="clear"></div>
    <div id="author_profile_honor"></div>
    <div id="author_profile_follow">
                <a href="javascript:void(0);" onclick="follow(&#39;4af65c58-15bf-e011-8673-842b2b196315&#39;);return false;">+加关注</a>
    </div>
</div>
<div id="div_digg">
    <div class="diggit" onclick="votePost(4815448,&#39;Digg&#39;)">
        <span class="diggnum" id="digg_count">0</span>
    </div>
    <div class="buryit" onclick="votePost(4815448,&#39;Bury&#39;)">
        <span class="burynum" id="bury_count">0</span>
    </div>
    <div class="clear"></div>
    <div class="diggword" id="digg_tips">
    </div>
</div>
</div>
<div class="clear"></div>
<div id="post_next_prev"><a href="http://www.cnblogs.com/xueyoo/p/4815357.html" class="p_n_p_prefix">« </a> 上一篇：<a href="http://www.cnblogs.com/xueyoo/p/4815357.html" title="发布于2015-09-17 09:36">Deep Learning（深度学习）学习笔记整理</a><br><a href="http://www.cnblogs.com/xueyoo/p/4818303.html" class="p_n_p_prefix">» </a> 下一篇：<a href="http://www.cnblogs.com/xueyoo/p/4818303.html" title="发布于2015-09-18 09:38">回归(regression)、梯度下降(gradient descent)</a><br></div>
</div>


		</div>
		<p class="postfoot">
			posted on <span id="post-date">2015-09-17 10:03</span> <a href="http://www.cnblogs.com/xueyoo/">xueyoo</a> 阅读(<span id="post_view_count">474</span>) 评论(<span id="post_comment_count">1</span>)  <a href="https://i.cnblogs.com/EditPosts.aspx?postid=4815448" rel="nofollow">编辑</a> <a href="http://www.cnblogs.com/xueyoo/p/4815448.html#" onclick="AddToWz(4815448);return false;">收藏</a>
		</p>
	</div>
	<script type="text/javascript">var allowComments=true,cb_blogId=245083,cb_entryId=4815448,cb_blogApp=currentBlogApp,cb_blogUserGuid='4af65c58-15bf-e011-8673-842b2b196315',cb_entryCreatedDate='2015/9/17 10:03:00';loadViewCount(cb_entryId);</script>
	
	</div><a name="!comments"></a><div id="blog-comments-placeholder"><div id="comments_pager_top"></div>
<a name="评论"></a>
<div id="comments">
<h3>评论</h3>
	
	
			<div class="post">
				<h2>
					<a href="http://www.cnblogs.com/xueyoo/p/4815448.html#3499891" class="layer">#1楼</a><a name="3499891" id="comment_anchor_3499891"></a><span id="comment-maxId" style="display:none;">3499891</span><span id="comment-maxDate" style="display:none;">2016/8/30 21:24:43</span>
					&nbsp;&nbsp;<span class="comment_actions"></span>
				</h2>
				<div id="comment_body_3499891" class="blog_comment_body">感谢你的博客，让我的写出了一个语法解析器的雏形。<br>目前我想使用phoenix::bind来处理表达式的变量，但是失败了，是类型的问题。请问factor.val = boost::phoenix::bind(get_value,arg1)， 这个get_value应该怎么写？是什么类型的返回值？</div><div class="comment_vote"><a href="javascript:void(0);" class="comment_digg" onclick="return voteComment(3499891,&#39;Digg&#39;,this)">支持(0)</a><a href="javascript:void(0);" class="comment_bury" onclick="return voteComment(3499891,&#39;Bury&#39;,this)">反对(0)</a></div>
				<div class="postfoot">
					 <span class="comment_date">2016-08-30 21:24</span> | <a id="a_comment_author_3499891" href="http://home.cnblogs.com/u/1018046/" target="_blank">nwpunene</a> <a href="http://msg.cnblogs.com/send/nwpunene" title="发送站内短消息" class="sendMsg2This">&nbsp;</a>
				</div>
			</div>
		
</div>
<div id="comments_pager_bottom"></div></div><script type="text/javascript">var commentManager = new blogCommentManager();commentManager.renderComments(0);</script>
<div id="comment_form" class="commentform">
<a name="commentform"></a>
<div id="divCommentShow"></div>
<div id="comment_nav"><span id="span_refresh_tips"></span><a href="javascript:void(0);" onclick="return RefreshCommentList();" id="lnk_RefreshComments" runat="server" clientidmode="Static">刷新评论</a><a href="http://www.cnblogs.com/xueyoo/p/4815448.html#" onclick="return RefreshPage();">刷新页面</a><a href="http://www.cnblogs.com/xueyoo/p/4815448.html#top">返回顶部</a></div>
<div id="comment_form_container"><div class="login_tips">注册用户登录后才能发表评论，请 <a rel="nofollow" href="javascript:void(0);" class="underline" onclick="return login(&#39;commentform&#39;);">登录</a> 或 <a rel="nofollow" href="javascript:void(0);" class="underline" onclick="return register();">注册</a>，<a href="http://www.cnblogs.com/">访问</a>网站首页。</div></div>
<div class="ad_text_commentbox" id="ad_text_under_commentbox"></div>
<div id="ad_t2"><a href="http://www.ucancode.com/index.htm" target="_blank">【推荐】50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库</a><br><a href="https://cloud.tencent.com/developer/labs?fromSource=gwzcw.436876.436876.436876" target="_blank">【推荐】腾讯云上实验室 1小时搭建人工智能应用</a><br><a href="http://www.gcpowertools.com.cn/products/spreadjs/?utm_source=cnblogs&amp;utm_medium=blogpage&amp;utm_term=bottom&amp;utm_content=SpreadJS&amp;utm_campaign=community" target="_blank">【推荐】可嵌入您系统的“在线Excel”！SpreadJS 纯前端表格控件</a><br><a href="http://click.aliyun.com/m/18488/" target="_blank">【推荐】阿里云“全民云计算”优惠升级</a><br></div>
<div id="opt_under_post"></div>
<div id="cnblogs_c1" class="c_ad_block"><a href="https://www.mtyun.com/promote/69f73a72-f46d-4103-88e5-94ed2f81259d/" target="_blank"><img width="300" height="250" src="./Boost学习之语法解析器--Spirit - xueyoo - 博客园_files/24442-20170921101521025-1845913848.jpg" alt="美团云0921"></a></div>
<div id="under_post_news"><div class="itnews c_ad_block"><b>最新IT新闻</b>:<br> ·  <a href="http://news.cnblogs.com/n/578757/" target="_blank">刘强东竟然以这种方式潜入A股！</a><br> ·  <a href="http://news.cnblogs.com/n/578766/" target="_blank">百世集团挂牌纽交所：募资4.5亿美元 阿里是其最大股东</a><br> ·  <a href="http://news.cnblogs.com/n/578765/" target="_blank">期待已久的Java 9今日发布</a><br> ·  <a href="http://news.cnblogs.com/n/578764/" target="_blank">CEO下班后逮住一个陌生人，引发经济间谍调查</a><br> ·  <a href="http://news.cnblogs.com/n/578763/" target="_blank">惠普宣布国际空间站太空超级计算机已经成功加电</a><br>» <a href="http://news.cnblogs.com/" title="IT新闻" target="_blank">更多新闻...</a></div></div>
<div id="cnblogs_c2" class="c_ad_block"><a href="https://www.jiguang.cn/devservice?source=bky&amp;hmsr=%E5%8D%9A%E5%AE%A2%E5%9B%AD&amp;hmpl=&amp;hmcu=&amp;hmkw=&amp;hmci=" target="_blank"><img width="468" height="60" src="./Boost学习之语法解析器--Spirit - xueyoo - 博客园_files/24442-20170908132742304-1045119416.gif" alt="极光0908"></a></div>
<div id="under_post_kb"><div class="itnews c_ad_block" id="kb_block"><b>最新知识库文章</b>:<br><div id="kb_recent"> ·  <a href="http://kb.cnblogs.com/page/576251/" target="_blank">如何阅读计算机科学类的书</a><br> ·  <a href="http://kb.cnblogs.com/page/578103/" target="_blank">Google 及其云智慧</a><br> ·  <a href="http://kb.cnblogs.com/page/575829/" target="_blank">做到这一点，你也可以成为优秀的程序员</a><br> ·  <a href="http://kb.cnblogs.com/page/566880/" target="_blank">写给立志做码农的大学生</a><br> ·  <a href="http://kb.cnblogs.com/page/569057/" target="_blank">架构腐化之谜</a><br></div>» <a href="http://kb.cnblogs.com/" target="_blank">更多知识库文章...</a></div></div>
<div id="HistoryToday" class="c_ad_block"></div>
<script type="text/javascript">
    fixPostBody();
    setTimeout(function () { incrementViewCount(cb_entryId); }, 50);
    deliverAdT2();
    deliverAdC1();
    deliverAdC2();    
    loadNewsAndKb();
    loadBlogSignature();
    LoadPostInfoBlock(cb_blogId, cb_entryId, cb_blogApp, cb_blogUserGuid);
    GetPrevNextPost(cb_entryId, cb_blogId, cb_entryCreatedDate);
    loadOptUnderPost();
    GetHistoryToday(cb_blogId, cb_blogApp, cb_entryCreatedDate);   
</script>
</div>


</div>
</div>
<div id="leftmenu">


<h3>导航</h3>
<ul>
<li>
<a id="blog_nav_sitehome" href="http://www.cnblogs.com/">博客园</a></li>
<li>
<a id="blog_nav_myhome" class="two_words" href="http://www.cnblogs.com/xueyoo/">首页</a></li>
<li>
<a id="blog_nav_newpost" rel="nofollow" href="https://i.cnblogs.com/EditPosts.aspx?opt=1">新随笔</a></li>
<li>
<a id="blog_nav_contact" accesskey="9" class="two_words" rel="nofollow" href="https://msg.cnblogs.com/send/xueyoo">联系</a></li>
<li>
<a id="blog_nav_rss" class="two_words" href="http://www.cnblogs.com/xueyoo/rss">订阅</a>
<a id="blog_nav_rss_image" href="http://www.cnblogs.com/xueyoo/rss"><img src="./Boost学习之语法解析器--Spirit - xueyoo - 博客园_files/xml.gif" alt="订阅"></a>
</li>
<li>
<a id="blog_nav_admin" class="two_words" rel="nofollow" href="https://i.cnblogs.com/">管理</a></li>
</ul>

<div id="blog-calendar" style=""><table id="blogCalendar" class="Cal" cellspacing="0" cellpadding="0" title="Calendar">
	<tbody><tr><td colspan="7"><table class="CalTitle" cellspacing="0">
		<tbody><tr><td class="CalNextPrev"><a href="javascript:void(0);" onclick="loadBlogCalendar(&#39;2017/08/01&#39;);return false;">&lt;</a></td><td align="center">2017年9月</td><td class="CalNextPrev" align="right"><a href="javascript:void(0);" onclick="loadBlogCalendar(&#39;2017/10/01&#39;);return false;">&gt;</a></td></tr>
	</tbody></table></td></tr><tr><th class="CalDayHeader" align="center" abbr="日" scope="col">日</th><th class="CalDayHeader" align="center" abbr="一" scope="col">一</th><th class="CalDayHeader" align="center" abbr="二" scope="col">二</th><th class="CalDayHeader" align="center" abbr="三" scope="col">三</th><th class="CalDayHeader" align="center" abbr="四" scope="col">四</th><th class="CalDayHeader" align="center" abbr="五" scope="col">五</th><th class="CalDayHeader" align="center" abbr="六" scope="col">六</th></tr><tr><td class="CalOtherMonthDay" align="center">27</td><td class="CalOtherMonthDay" align="center">28</td><td class="CalOtherMonthDay" align="center">29</td><td class="CalOtherMonthDay" align="center">30</td><td class="CalOtherMonthDay" align="center">31</td><td align="center">1</td><td class="CalWeekendDay" align="center">2</td></tr><tr><td class="CalWeekendDay" align="center">3</td><td align="center">4</td><td align="center">5</td><td align="center">6</td><td align="center">7</td><td align="center">8</td><td class="CalWeekendDay" align="center">9</td></tr><tr><td class="CalWeekendDay" align="center">10</td><td align="center">11</td><td align="center">12</td><td align="center">13</td><td align="center">14</td><td align="center">15</td><td class="CalWeekendDay" align="center">16</td></tr><tr><td class="CalWeekendDay" align="center">17</td><td align="center">18</td><td align="center">19</td><td align="center">20</td><td class="CalTodayDay" align="center">21</td><td align="center">22</td><td class="CalWeekendDay" align="center">23</td></tr><tr><td class="CalWeekendDay" align="center">24</td><td align="center">25</td><td align="center">26</td><td align="center">27</td><td align="center">28</td><td align="center">29</td><td class="CalWeekendDay" align="center">30</td></tr><tr><td class="CalOtherMonthDay" align="center">1</td><td class="CalOtherMonthDay" align="center">2</td><td class="CalOtherMonthDay" align="center">3</td><td class="CalOtherMonthDay" align="center">4</td><td class="CalOtherMonthDay" align="center">5</td><td class="CalOtherMonthDay" align="center">6</td><td class="CalOtherMonthDay" align="center">7</td></tr>
</tbody></table></div><script type="text/javascript">loadBlogDefaultCalendar();</script>
<meta name="vs_showGrid" content="False">

<h3>公告</h3>
<div id="blog-news"><div id="profile_block">昵称：<a href="http://home.cnblogs.com/u/xueyoo/">xueyoo</a><br>园龄：<a href="http://home.cnblogs.com/u/xueyoo/" title="入园时间：2011-08-05">6年1个月</a><br>粉丝：<a href="http://home.cnblogs.com/u/xueyoo/followers/">1</a><br>关注：<a href="http://home.cnblogs.com/u/xueyoo/followees/">0</a><div id="p_b_follow"><a href="javascript:void(0);" onclick="follow(&#39;4af65c58-15bf-e011-8673-842b2b196315&#39;)">+加关注</a></div></div></div><script type="text/javascript">loadBlogNews();</script>

<div id="blog-sidecolumn"><div id="sidebar_search" class="sidebar-block">
<div id="sidebar_search" class="mySearch">
<h3 class="catListTitle">搜索</h3>
<div id="sidebar_search_box">
<div id="widget_my_zzk" class="div_my_zzk"><input type="text" id="q" onkeydown="return zzk_go_enter(event);" class="input_my_zzk">&nbsp;<input onclick="zzk_go()" type="button" value="找找看" id="btnZzk" class="btn_my_zzk"></div>
<div id="widget_my_google" class="div_my_zzk"><input type="text" name="google_q" id="google_q" onkeydown="return google_go_enter(event)" class="input_my_zzk">&nbsp;<input onclick="google_go()" type="button" value="谷歌搜索" class="btn_my_zzk"></div>
</div>
</div>

</div><div id="sidebar_shortcut" class="sidebar-block">
<h3 class="catListTitle">常用链接</h3>
<ul>
<li><a href="http://www.cnblogs.com/xueyoo/p/" title="我的博客的随笔列表">我的随笔</a></li><li><a href="http://www.cnblogs.com/xueyoo/MyComments.html" title="我发表过的评论列表">我的评论</a></li><li><a href="http://www.cnblogs.com/xueyoo/OtherPosts.html" title="我评论过的随笔列表">我的参与</a></li><li><a href="http://www.cnblogs.com/xueyoo/RecentComments.html" title="我的博客的评论列表">最新评论</a></li><li><a href="http://www.cnblogs.com/xueyoo/tag/" title="我的博客的标签列表">我的标签</a></li>
</ul>
<div id="itemListLin_con" style="display:none;">

</div></div><div id="sidebar_toptags" class="sidebar-block"></div><div id="sidebar_categories">
		<h3>随笔分类</h3>
		
				<ul>
			
				<li><a id="CatList_LinkList_0_Link_0" href="http://www.cnblogs.com/xueyoo/category/735670.html">C/C++(1)</a></li>
			
				<li><a id="CatList_LinkList_0_Link_1" href="http://www.cnblogs.com/xueyoo/category/735640.html">人工智能(8)</a></li>
			
				</ul>
			
	
		<h3>随笔档案</h3>
		
				<ul>
			
				<li><a id="CatList_LinkList_1_Link_0" href="http://www.cnblogs.com/xueyoo/archive/2015/10.html">2015年10月 (2)</a></li>
			
				<li><a id="CatList_LinkList_1_Link_1" href="http://www.cnblogs.com/xueyoo/archive/2015/09.html">2015年9月 (9)</a></li>
			
				</ul>
			
	
		<h3>文章分类</h3>
		
				<ul>
			
				<li><a id="CatList_LinkList_2_Link_0" href="http://www.cnblogs.com/xueyoo/category/737617.html">单片机/嵌入式(7)</a></li>
			
				<li><a id="CatList_LinkList_2_Link_1" href="http://www.cnblogs.com/xueyoo/category/752133.html">反汇编(4)</a></li>
			
				</ul>
			
	
		<h3>相册</h3>
		
				<ul>
			
				<li><a id="CatList_LinkList_3_Link_0" href="http://www.cnblogs.com/xueyoo/gallery/740040.html" rel="nofollow">默认相册</a></li>
			
				</ul>
			
	</div><div id="sidebar_recentcomments" class="sidebar-block"><div id="recent_comments_wrap">
<h3 class="catListTitle">最新评论</h3>
<div class="RecentComment" id="RecentComments">
	<div id="RecentCommentsBlock"><ul>
        <li class="recent_comment_title"><a href="http://www.cnblogs.com/xueyoo/articles/4929580.html#3685547">1. Re:FPGA Verilog语言中阻塞赋值与非阻塞赋值个人看法</a></li>
        <li class="recent_comment_body">求继续分析两个同时赋值是什么结果？</li>
        <li class="recent_comment_author">--Blondig</li>
        <li class="recent_comment_title"><a href="http://www.cnblogs.com/xueyoo/p/4815448.html#3499891">2. Re:Boost学习之语法解析器--Spirit</a></li>
        <li class="recent_comment_body">感谢你的博客，让我的写出了一个语法解析器的雏形。目前我想使用phoenix::bind来处理表达式的变量，但是失败了，是类型的问题。请问factor.val = boost::phoenix::bin......</li>
        <li class="recent_comment_author">--nwpunene</li>
</ul>
</div>
</div>
</div></div><div id="sidebar_topviewedposts" class="sidebar-block"><div id="topview_posts_wrap">
<h3 class="catListTitle">阅读排行榜</h3>
<div class="RecentComment" id="TopViewPosts"> 
	<div id="TopViewPostsBlock"><ul><li><a href="http://www.cnblogs.com/xueyoo/p/4812728.html">1. 特征工程 vs. 特征提取(1401)</a></li><li><a href="http://www.cnblogs.com/xueyoo/p/4815448.html">2. Boost学习之语法解析器--Spirit(474)</a></li><li><a href="http://www.cnblogs.com/xueyoo/p/4812711.html">3. 递归神经网络不可思议的有效性(90)</a></li><li><a href="http://www.cnblogs.com/xueyoo/p/4814131.html">4. Caffe 深度学习框架上手教程(59)</a></li><li><a href="http://www.cnblogs.com/xueyoo/p/4812685.html">5. 各种编程语言的深度学习库整理(48)</a></li></ul></div>
</div>
</div></div><div id="sidebar_topcommentedposts" class="sidebar-block"><div id="topfeedback_posts_wrap">
<h3 class="catListTitle">评论排行榜</h3>
<div class="RecentComment" id="TopCommentsPosts">
	<div id="TopFeedbackPostsBlock"><ul><li><a href="http://www.cnblogs.com/xueyoo/p/4815448.html">1. Boost学习之语法解析器--Spirit(1)</a></li></ul></div>
</div></div></div><div id="sidebar_topdiggedposts" class="sidebar-block"><div id="topdigg_posts_wrap">
<h3 class="catListTitle">推荐排行榜</h3>
<div class="RecentComment">
	<div id="TopDiggPostsBlock"><ul><li><a href="http://www.cnblogs.com/xueyoo/p/4812685.html">1. 各种编程语言的深度学习库整理(1)</a></li></ul></div>
</div></div></div></div><script type="text/javascript">loadBlogSideColumn();</script>

</div>
</div>
<div class="clear"></div>
<div id="footer">

<p id="footer">
	Powered by: 
	<br>
	
	<a id="Footer1_Hyperlink3" name="Hyperlink1" href="http://www.cnblogs.com/" style="font-family:Verdana;font-size:12px;">博客园</a>
	<br>
	Copyright © xueyoo
</p>
</div>
</div>



</body></html>